{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "7292e8f4-a8c2-4cb3-8dc3-6300be2e232f",
   "metadata": {},
   "source": [
    "### Exploring Chemical and Biological Data With BidingDB and the RDKit\n",
    "In this notebook we will use the [BindingDB](https://bindingdb.org/rwd/bind/index.jsp), database of chemical structures and biological activity values extracted from the chemical literature, to search for compounds that bind to the [SARS-CoV-2 main  protease](https://pubmed.ncbi.nlm.nih.gov/35845352/).  In addition to hosting data from the scientifiic literature, BindingDB also has data extracted from chemical patents.  We will extract the data from a SARS-CoV-2 inhibitor patent, explore this data, and save a representative subset for a subsequent docking analysis. "
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "87d30109-723d-41c1-95b3-93f18f430919",
   "metadata": {},
   "source": [
    "### 1. Searching BindingDB and Downloading Chemical Structures and Data\n",
    "We begin by accessing the BindingDB website at [https://bindingdb.org](https://bindingdb.org). Click on the **Publications** link on the left, then click on the **US Patent** link. \n",
    "   \n",
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/refs/heads/main/pdb/binding_db_01.png\"/>     \n",
    "   \n",
    "This will bring up a results page like the one below.  This page shows recently curated patents and allows us to search by patent number.  Enter this text into the box, [US20240293380](https://patents.google.com/patent/US20240293380A1/fr).  Once you click on the **Search** button, BindingDB will find compounds that were curated from this patent by scientists as the Cleveland Clinic, describing a set of protease inhibitors. \n",
    "   \n",
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/refs/heads/main/pdb/binding_db_02.png\"/>  \n",
    "   \n",
    "This will take you to a page with details the 75 compounds extracted from US20240293380.  The page shows chemical structures as well as links to other databases. To download the information about all structures from this patent, first click on the **Add all pages** link, followed by the **Make dataset** button indicated by the arrows in figure below. \n",
    "   \n",
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/refs/heads/main/pdb/binding_db_03.png\"/>   \n",
    "   \n",
    "By selecting the **Tab Delimited (TSV)** radio button and pressing the **Go** button, we can download the data.  This download requires registration with BindingDB.  To streamline this tutorial, we will load the file directly from GitHub instead. \n",
    "   \n",
    "<img src=\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/refs/heads/main/pdb/binding_db_04.png\"/>    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33813b32-fb34-4619-9626-2570314da35b",
   "metadata": {},
   "source": [
    "### 2. Install and Import the necessary Python libraries\n",
    "The next cell will install the Python libraries necessary for this notebook.  Note that the libraries are only installed if the notebook is running in Google Colab.  The installation process generates a lot of output, which we suppress with the **%%caputure%%** magic command.  If you run into problems, remove **%%capture%%** to see the cell output. "
   ]
  },
  {
   "cell_type": "code",
   "id": "86ecf69a-363e-42c1-aa39-9743c98fea00",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.360816Z",
     "start_time": "2025-05-06T01:16:06.357749Z"
    }
   },
   "source": [
    "%%capture\n",
    "import sys\n",
    "IN_COLAB = 'google.colab' in sys.modules\n",
    "if IN_COLAB:\n",
    "    !pip install pandas mols2grid seaborn rdkit matplotlib useful_rdkit_utils scikit-learn ipywidgets"
   ],
   "outputs": [],
   "execution_count": 39
  },
  {
   "cell_type": "markdown",
   "id": "7e438f85-f87e-4189-922f-c36b90c4bf4a",
   "metadata": {},
   "source": [
    "We are the capabilities provided by these libraries. \n",
    "\n",
    "- [pandas](https://pandas.pydata.org/) - data analysis and manipulation\n",
    "- [mols2grid](https://github.com/cbouy/mols2grid) - display interactive grids of chemical structures and data\n",
    "- [seaborn](https://seaborn.pydata.org/) - plotting and data visualization\n",
    "- [rdkit](https://www.rdkit.org/) - Open source cheminformatics\n",
    "- [matplotlib](https://matplotlib.org/) - data visualization\n",
    "- [useful_rdkit_utils](https://useful-rdkit-utils.readthedocs.io/en/latest/) - Cheminformatics utilities\n",
    "- [scikit-learn](https://scikit-learn.org/stable/) - Machine learning\n",
    "- [ipywidgets](https://ipywidgets.readthedocs.io/en/stable/) - Interactive tools in Jupyter notebooks"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c123a41-5301-4017-980b-7731583d228d",
   "metadata": {},
   "source": [
    "In the cell below, we load the python libraries"
   ]
  },
  {
   "cell_type": "code",
   "id": "5bff75b8-4b18-449e-9e48-cadfad05677e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.382714Z",
     "start_time": "2025-05-06T01:16:06.380575Z"
    }
   },
   "source": [
    "import pandas as pd\n",
    "import mols2grid\n",
    "import seaborn as sns\n",
    "import numpy as np\n",
    "from rdkit import Chem\n",
    "from rdkit.Chem import rdFMCS\n",
    "from rdkit.Chem.Scaffolds.MurckoScaffold import GetScaffoldForMol\n",
    "import useful_rdkit_utils as uru\n",
    "from IPython.core.display import HTML"
   ],
   "outputs": [],
   "execution_count": 40
  },
  {
   "cell_type": "markdown",
   "id": "d5f9b7ac-bc09-4e3b-b4cc-c55b393808c5",
   "metadata": {},
   "source": [
    "### 3. Read the file we downloaded from PDBBind into a Pandas dataframe. "
   ]
  },
  {
   "cell_type": "code",
   "id": "cea639bd-5492-4023-808c-0a6523ecf257",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.529135Z",
     "start_time": "2025-05-06T01:16:06.385751Z"
    }
   },
   "source": [
    "df = pd.read_csv(\"https://raw.githubusercontent.com/PatWalters/practical_cheminformatics_tutorials/refs/heads/main/pdb/monomers_12285.tsv\",sep=\"\\t\")"
   ],
   "outputs": [],
   "execution_count": 41
  },
  {
   "cell_type": "markdown",
   "id": "3e53ea31-b52e-4690-91dd-643d632ce11c",
   "metadata": {},
   "source": [
    "As we can see, the data we extracted from BindingDB has many fields. "
   ]
  },
  {
   "cell_type": "code",
   "id": "cebbdfc9-fcc7-4b23-8e45-b2116fed6c06",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.542423Z",
     "start_time": "2025-05-06T01:16:06.540273Z"
    }
   },
   "source": [
    "df.columns"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Index(['BindingDB Reactant_set_id', 'Ligand SMILES', 'Ligand InChI',\n",
       "       'Ligand InChI Key', 'BindingDB MonomerID', 'BindingDB Ligand Name',\n",
       "       'Target Name',\n",
       "       'Target Source Organism According to Curator or DataSource', 'Ki (nM)',\n",
       "       'IC50 (nM)', 'Kd (nM)', 'EC50 (nM)', 'kon (M-1-s-1)', 'koff (s-1)',\n",
       "       'pH', 'Temp (C)', 'Curation/DataSource', 'Article DOI',\n",
       "       'BindingDB Entry DOI', 'PMID', 'PubChem AID', 'Patent Number',\n",
       "       'Authors', 'Institution', 'Link to Ligand in BindingDB',\n",
       "       'Link to Target in BindingDB',\n",
       "       'Link to Ligand-Target Pair in BindingDB', 'Ligand HET ID in PDB',\n",
       "       'PDB ID(s) for Ligand-Target Complex', 'PubChem CID of Ligand',\n",
       "       'PubChem SID of Ligand', 'ChEBI ID of Ligand', 'ChEMBL ID of Ligand',\n",
       "       'DrugBank ID of Ligand', 'IUPHAR_GRAC ID of Ligand',\n",
       "       'KEGG ID of Ligand', 'ZINC ID of Ligand',\n",
       "       'Number of Protein Chains in Target (>1 implies a multichain complex)',\n",
       "       'BindingDB Target Chain Sequence', 'PDB ID(s) of Target Chain',\n",
       "       'UniProt (SwissProt) Recommended Name of Target Chain',\n",
       "       'UniProt (SwissProt) Entry Name of Target Chain',\n",
       "       'UniProt (SwissProt) Primary ID of Target Chain',\n",
       "       'UniProt (SwissProt) Secondary ID(s) of Target Chain',\n",
       "       'UniProt (SwissProt) Alternative ID(s) of Target Chain',\n",
       "       'UniProt (TrEMBL) Submitted Name of Target Chain',\n",
       "       'UniProt (TrEMBL) Entry Name of Target Chain',\n",
       "       'UniProt (TrEMBL) Primary ID of Target Chain',\n",
       "       'UniProt (TrEMBL) Secondary ID(s) of Target Chain',\n",
       "       'UniProt (TrEMBL) Alternative ID(s) of Target Chain'],\n",
       "      dtype='object')"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 42
  },
  {
   "cell_type": "markdown",
   "id": "7a73360d-304f-4c52-a063-a77007addbbd",
   "metadata": {},
   "source": [
    "To make things simpler, we'll rename a couple of columns."
   ]
  },
  {
   "cell_type": "code",
   "id": "04f3e39d-fbf4-4808-ac42-c6602fb0e896",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.555350Z",
     "start_time": "2025-05-06T01:16:06.553267Z"
    }
   },
   "source": [
    "df.rename(columns={'Ligand SMILES':'SMILES'},inplace=True)\n",
    "df.rename(columns={'BindingDB Ligand Name':'Name'},inplace=True)"
   ],
   "outputs": [],
   "execution_count": 43
  },
  {
   "cell_type": "markdown",
   "id": "073c89bd-33ad-48eb-a5be-d4d61efe1de6",
   "metadata": {},
   "source": [
    "We can aslo see that the data has 75 rows, with each compound corresponding to a row.  For our purposes, we'll focus on a few fields. \n",
    "- SMILES - the chemical structure of the compound\n",
    "- Name - the internal identifier Binding DB provides for each compund\n",
    "- IC50 (nM) - the IC50 in nM.\n",
    "\n",
    "The IC50, or half maximal inhibitory concentration, is a measure of a substance's potency in inhibiting a specific biological or biochemical function. It represents the concentration of an inhibitor needed to reduce a particular biological process or component by 50% in vitro, and is commonly used to assess the effectiveness of drugs in pharmacological research. IC50 values are typically expressed as nM concentrations and provide a quantitative indication of how much of an inhibitory substance is required to achieve half-maximal inhibition of a given target or process"
   ]
  },
  {
   "cell_type": "code",
   "id": "b7c07462-8238-46ef-b171-65e103d0a83f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.567633Z",
     "start_time": "2025-05-06T01:16:06.565544Z"
    }
   },
   "source": [
    "len(df)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "75"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 44
  },
  {
   "cell_type": "markdown",
   "id": "be1dc358-bbe6-41c9-85fd-d0ea0d955d3d",
   "metadata": {},
   "source": [
    "We can use [mols2grid](https://github.com/cbouy/mols2grid) to browse the chemcial structures of the 75 compounds. "
   ]
  },
  {
   "cell_type": "code",
   "id": "075e6dc4-a36b-451d-9c97-55d03999be9c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.585384Z",
     "start_time": "2025-05-06T01:16:06.579357Z"
    }
   },
   "source": [
    "mols2grid.display(df,smiles_col=\"SMILES\",subset=[\"img\",\"IC50 (nM)\"])"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MolGridWidget()"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "6bb6552457fc4db5834c9f204e1e4b21"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<style>\n",
       "    /* Some CSS to integrate with Jupyter more cleanly */\n",
       "    div.output_subarea {\n",
       "        /* Undo an unfortunate max-width parameter\n",
       "        that causes the output area to be too narrow\n",
       "        on smaller screens. */\n",
       "        max-width: none;\n",
       "\n",
       "        /* Align the table with the content */\n",
       "        padding: 0;\n",
       "\n",
       "        /* Let it breathe */\n",
       "        margin-top: 20px;\n",
       "    }\n",
       "</style>\n",
       "\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "    \n",
       "    \n",
       "    allow=\"clipboard-write\"\n",
       "    \n",
       "    \n",
       "    sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
       "    \n",
       "    srcdoc=\"\n",
       "\n",
       "\n",
       "\n",
       "&lt;html lang=&quot;en&quot;&gt;\n",
       "    &lt;head&gt;\n",
       "        &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
       "        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
       "        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
       "        &lt;title&gt;Document!&lt;/title&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;style&gt;\n",
       "            /**\n",
       " * General styling\n",
       " */\n",
       "body {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "}\n",
       "h1,h2,h3,h4 {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "h1 {\n",
       "    font-size: 26px;\n",
       "}\n",
       "h2 {\n",
       "    font-size: 20px;\n",
       "    font-weight: 400;\n",
       "}\n",
       "h3 {\n",
       "\tfont-size: 16px;\n",
       "}\n",
       "p {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "\n",
       "\n",
       "/* Remove body margin inside iframe */\n",
       "body.m2g-inside-iframe {\n",
       "    margin: 0;\n",
       "}\n",
       "\n",
       "/* In-cell text */\n",
       "#mols2grid .data:not(.data-img) {\n",
       "    height: 16px;\n",
       "    line-height: 16px;\n",
       "}\n",
       "/* Text truncation */\n",
       "#mols2grid .data {\n",
       "    /* Break text into multiple lines (default for static)... */\n",
       "    word-wrap: normal;\n",
       "\n",
       "    /* ...or truncate it (default for interactive). */\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "}\n",
       "\n",
       "\n",
       "/**\n",
       " * Popover\n",
       " * - - -\n",
       " * Note: this is a bootstrap variable which is not namespaced.\n",
       " * To avoid any contamination, we only style it when the\n",
       " * x-placement parameter is set.\n",
       " */\n",
       ".popover[x-placement] {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    background: white;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    font-size: 12px;\n",
       "    padding: 10px;\n",
       "    border-radius: 5px;\n",
       "    box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
       "    user-select: none;\n",
       "}\n",
       ".popover[x-placement] h3 {\n",
       "    margin: 0;\n",
       "}\n",
       ".popover[x-placement] .arrow {\n",
       "    width: 10px;\n",
       "    height: 10px;\n",
       "    background: #fff;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    box-sizing: border-box;\n",
       "    position: absolute;\n",
       "    transform-origin: 5px 5px;\n",
       "    clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
       "}\n",
       ".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
       "    transform: rotate(45deg);\n",
       "    top: 50%;\n",
       "    right: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
       "    transform: rotate(-135deg);\n",
       "    top: 50%;\n",
       "    left: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
       "    transform: rotate(135deg);\n",
       "    left: 50%;\n",
       "    bottom: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
       "    transform: rotate(-45deg);\n",
       "    left: 50%;\n",
       "    top: -5px;\n",
       "}\n",
       "            body {\n",
       "    /* Colors */\n",
       "    --m2g-black: rgba(0,0,0,.75);\n",
       "    --m2g-black-soft: rgba(0,0,0,.35);\n",
       "    --m2g-black-10: rgba(0,0,0,.1);\n",
       "    --m2g-bg: #f6f6f6;\n",
       "    --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
       "    --m2g-hl: #555; /* Highlight color */\n",
       "    --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
       "    --m2g-blue: #0f62fe;\n",
       "    --m2g-blue-soft: rgba(15,98,254,.2);\n",
       "\n",
       "    /* Icons */\n",
       "    --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    \n",
       "    /* Border radius */\n",
       "    --m2g-br: 3px;\n",
       "    --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
       "    --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
       "\n",
       "    /* Text */\n",
       "    --m2g-fs: 14px; /* UI font-size */\n",
       "    --m2g-fs-cell: 12px; /* Cell font-size */\n",
       "\n",
       "    /* Transition speeds */\n",
       "    --m2g-trans: 150ms;\n",
       "\n",
       "    /* Layout */\n",
       "    --m2g-h: 40px; /* Form element height */\n",
       "}\n",
       "\n",
       "/* Styling */\n",
       "#mols2grid {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: var(--m2g-fs);\n",
       "}\n",
       "\n",
       "/* Fixes */\n",
       "#mols2grid *,\n",
       "#mols2grid *::before,\n",
       "#mols2grid *::after {\n",
       "    box-sizing: border-box;\n",
       "    outline: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-functions {\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row {\n",
       "    flex: 0;\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Individual elements don&#x27;t scale */\n",
       "#mols2grid .m2g-functions .m2g-row &gt; * {\n",
       "    flex: 0 0;\n",
       "    margin-right: 10px;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Row 1: pagination + gap + sort */\n",
       "#mols2grid .m2g-functions .m2g-row:first-child {\n",
       "    flex: 1; /* Scale */\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-gap {\n",
       "    /* The gap in between will scale, so the pagination\n",
       "    stays on the left, while the rest moves to the right */\n",
       "    flex: 1;\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Pagination\n",
       " */\n",
       "\n",
       "#mols2grid ul.m2g-pagination {\n",
       "    /* Unset defaults */\n",
       "    list-style-type: none;\n",
       "    margin-block-start: 0;\n",
       "    margin-block-end: 0;\n",
       "    margin-inline-start: 0;\n",
       "    margin-inline-end: 0;\n",
       "    padding-inline-start: 0;\n",
       "\n",
       "    /* Custom */\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li {\n",
       "    background: var(--m2g-bg) ;\n",
       "    border: var(--m2g-border);\n",
       "    height: var(--m2g-h);\n",
       "    min-width: calc(var(--m2g-h) + 1px);\n",
       "    position: relative;\n",
       "    user-select: none;\n",
       "    \n",
       "    /* Compensate for double border */\n",
       "    margin-right: -1px;\n",
       "    \n",
       "    /* Center text */\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    min-width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li a {\n",
       "    text-decoration: none;\n",
       "    color: var(--m2g-black);\n",
       "    padding: 0 10px;\n",
       "    width: 100%;\n",
       "    height: var(--m2g-h);\n",
       "    line-height: var(--m2g-h);\n",
       "    text-align: center;\n",
       "    /* Compensate for border so there&#x27;s no gap between click areas  */\n",
       "    margin: 0 -1px;\n",
       "}\n",
       "\n",
       "/* Corner shape */\n",
       "#mols2grid ul.m2g-pagination li:first-child {\n",
       "    border-radius: var(--m2g-br-l);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    border-radius: var(--m2g-br-r);\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid ul.m2g-pagination li:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "    z-index: 1;\n",
       "}\n",
       "\n",
       "/* Active state */\n",
       "#mols2grid ul.m2g-pagination li.active {\n",
       "    background: var(--m2g-hl);\n",
       "    z-index: 1;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li.active a {\n",
       "    cursor: default;\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "/* Disabled sate */\n",
       "#mols2grid ul.m2g-pagination li.disabled a {\n",
       "    cursor: default;\n",
       "    color: rgba(0,0,0,.25);\n",
       "    pointer-events: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Dropdowns\n",
       " */\n",
       "\n",
       "#mols2grid ::placeholder {\n",
       "    color: var(--m2g-black-soft);\n",
       "}\n",
       "#mols2grid .m2g-dropdown {\n",
       "    height: var(--m2g-h);\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "    position: relative;\n",
       "}\n",
       "#mols2grid .m2g-dropdown select {\n",
       "    -webkit-appearance: none;\n",
       "    -moz-appearance: none;\n",
       "    -ms-appearance: none;\n",
       "    appearance: none;\n",
       "    background: transparent;\n",
       "    border: none;\n",
       "    height: 100%;\n",
       "    padding: 0 13px;\n",
       "    min-width: 0;\n",
       "    max-width: 250px;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "/* Icon */\n",
       "#mols2grid .m2g-dropdown .m2g-icon {\n",
       "    width: 30px;\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    pointer-events: none;\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
       "    fill: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
       "    stroke: var(--m2g-black);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "/* We hide the native select element because\n",
       " * it is limited in styling. Instead, we display\n",
       " * the selected value in a div. */\n",
       "#mols2grid .m2g-dropdown .m2g-display {\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    right: 0;\n",
       "    top: 0;\n",
       "    bottom: 0;\n",
       "    pointer-events: none;\n",
       "    color: var(--m2g-black);\n",
       "    line-height: var(--m2g-h);\n",
       "    padding: 0 25px 0 13px;\n",
       "\n",
       "    /* Truncate dropdown text */\n",
       "    white-space: nowrap;\n",
       "\ttext-overflow: ellipsis;\n",
       "\toverflow: hidden;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Action dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-actions {\n",
       "    width: var(--m2g-h);\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions select {\n",
       "    opacity: 0;\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Sort dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-sort {\n",
       "    flex: 0 0 200px;\n",
       "    width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
       "    border-radius: var(--m2g-br);\n",
       "    background: var(--m2g-bg);\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Dropdown */\n",
       "#mols2grid .m2g-dropdown.m2g-sort select {\n",
       "    flex: 1 1;\n",
       "    opacity: 0;\n",
       "    /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
       "    box-sizing: border-box;\n",
       "}\n",
       "\n",
       "/* Sort order */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    flex: 0 0 30px;\n",
       "    height: 100%;\n",
       "    border-left: var(--m2g-border);\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
       "    transform: rotate(180deg);\n",
       "    border-left: none;\n",
       "    border-right: var(--m2g-border);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
       "    right: 31px;\n",
       "    padding-right: 13px;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
       "    content: &#x27;Sort: &#x27;;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Search bar\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-search-wrap {\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: flex-end;\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "}\n",
       "#mols2grid .m2g-searchbar {\n",
       "    width: 170px;\n",
       "    height: var(--m2g-h);\n",
       "    padding: 0 13px;\n",
       "    border: none;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: text;\n",
       "    background: transparent;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-search-wrap:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Option buttons */\n",
       "#mols2grid .m2g-search-options {\n",
       "    font-size: 12px;\n",
       "    display: flex;\n",
       "    height: calc(1.5em + .75rem);\n",
       "    line-height: calc(1.5em + .75rem);\n",
       "    margin-right: 5px;\n",
       "    border-radius: var(--m2g-br);\n",
       "    color: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option {\n",
       "    background: var(--m2g-black-10);\n",
       "    padding: 0 13px;\n",
       "    cursor: default;\n",
       "    user-select: none;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:first-child {\n",
       "    border-radius: 2px 0 0 2px;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:last-child {\n",
       "    border-radius: 0 2px 2px 0;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option.sel {\n",
       "    background: var(--m2g-hl);\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#mols2grid .m2g-list {\n",
       "    display: flex;\n",
       "    flex-wrap: wrap;\n",
       "    align-items: flex-start;\n",
       "    justify-content: flex-start;\n",
       "    padding: 1px; /* Compensate for negative padding on cell */\n",
       "    user-select: none;\n",
       "    margin: 0px;\n",
       "    margin-top: 20px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    \n",
       "}\n",
       "\n",
       "/* Cell */\n",
       "#mols2grid .m2g-cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    font-family: var(--font-family);\n",
       "    padding: 10px;\n",
       "    padding-top: max(10px, 20px);\n",
       "    margin: -1px -1px 0 0;\n",
       "    flex: 1 0 130px;\n",
       "    position: relative;\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    cursor: pointer;\n",
       "    color: var(--m2g-black);\n",
       "    overflow: hidden;\n",
       "    box-sizing: border-box;\n",
       "    background-color: white;\n",
       "}\n",
       "#mols2grid .m2g-cell:focus {\n",
       "    z-index: 1;\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Phantom cells to maintain grid structure with less results */\n",
       "#mols2grid .m2g-cell.m2g-phantom {\n",
       "    border: none;\n",
       "    pointer-events: none;\n",
       "    height: 0;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       "/* Checkbox &amp; ID */\n",
       "#mols2grid .m2g-cb-wrap {\n",
       "    position: absolute;\n",
       "    top: 3px;\n",
       "    left: 3px;\n",
       "    display: flex;\n",
       "    border-radius: 2px;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    padding: 3px;\n",
       "    padding-right: 0;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
       "    display: none;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
       "\twidth: 16px;\n",
       "\theight: 16px;\n",
       "\tbox-sizing: border-box;\n",
       "\tbackground: #fff;\n",
       "\tborder: var(--m2g-border);\n",
       "\tborder-radius: 2px;\n",
       "    margin-right: 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
       "    border: none;\n",
       "    background-color: var(--m2g-blue);\n",
       "    background-image: var(--m2g-icn-cb-white);\n",
       "}\n",
       "#mols2grid .m2g-tooltip {\n",
       "    /* This is a div spanning full cell size where the\n",
       "    tooltip is rendered around, because you can&#x27;t attach\n",
       "    it to the parent due to list.js limitation. */\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    top: 0;\n",
       "    z-index: -1;\n",
       "    pointer-events: none;\n",
       "    opacity: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell:has(:checked) {\n",
       "    background: #ffd !important; /* Overrides user-set background color */\n",
       "}\n",
       "#mols2grid .data-mols2grid-id-display {\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    line-height: 16px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
       "    padding: 0 5px 0 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap .data-name-display {\n",
       "    font-size: var(--m2g-fs);\n",
       "    line-height: 16px;\n",
       "}\n",
       "\n",
       "/* Info + callback button wrap (28px high) */\n",
       "#mols2grid .m2g-cell-actions {\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    \n",
       "    /* background: yellow; */\n",
       "}\n",
       "\n",
       "/* Info button */\n",
       "#mols2grid .m2g-info {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    border-radius: 2px;\n",
       "    line-height: 28px;\n",
       "    font-size: min(14px, 12px);\n",
       "    font-family: Georgia, serif;\n",
       "    font-style: italic;\n",
       "    padding: 0;\n",
       "    text-align: center;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info {\n",
       "    color: #fff;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
       "    content: &#x27;i&#x27;;\n",
       "    width: 18px;\n",
       "    height: 18px;\n",
       "    line-height: 18px;\n",
       "    background: var(--m2g-hl);\n",
       "    position: absolute;\n",
       "    left: 5px;\n",
       "    top: 5px;\n",
       "    border-radius: 9px;\n",
       "}\n",
       "\n",
       "/* Callback button */\n",
       "#mols2grid .m2g-callback {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-callback::after {\n",
       "    content: &#x27;&#x27;;\n",
       "    display: block;\n",
       "    width: 16px;\n",
       "    height: 16px;\n",
       "    margin: 6px;\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: 2px;\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    transform: rotate(-90deg);\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#mols2grid .m2g-cell .data-img {\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell img,\n",
       "#mols2grid .m2g-cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
       "    /* Remove the SVG background */\n",
       "    fill: transparent !important;\n",
       "}\n",
       "\n",
       "/* Text below image */\n",
       ".m2g-copy-blink {\n",
       "    animation: m2g-blink var(--m2g-trans) 3;\n",
       "}\n",
       "@keyframes m2g-blink {\n",
       "    0% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    49% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    50% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "    100% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Copyable text */\n",
       ".copy-me {\n",
       "    position: relative;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Modal popup\n",
       " * - - -\n",
       " * Triggered by make_popup_callback()\n",
       " * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#m2g-modal-container {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    background: var(--m2g-black-10);\n",
       "    position: fixed;\n",
       "    top: 0;\n",
       "    left: 0;\n",
       "    z-index: 1;\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    \n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transition: opacity var(--m2g-trans) linear;\n",
       "}\n",
       "\n",
       "/* Modal */\n",
       "#m2g-modal {\n",
       "    background: #fff;\n",
       "    border-radius: var(--m2g-br);\n",
       "    box-shadow: 0 0 30px var(--m2g-black-10);\n",
       "    padding: 20px;\n",
       "    position: relative;\n",
       "    max-width: calc(100% - 80px);\n",
       "    max-height: calc(100% - 80px);\n",
       "    display: flex;\n",
       "    flex-direction: column;\n",
       "    min-width: 26px;\n",
       "\n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transform: translate(0, 5px);\n",
       "    transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header {\n",
       "    flex: 0 0 26px;\n",
       "    margin-bottom: 10px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 {\n",
       "    margin-bottom: 0;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 + p {\n",
       "    font-size: 15px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-body {\n",
       "    flex: 1;\n",
       "    position: relative;\n",
       "}\n",
       "\n",
       "/* Transition */\n",
       "#m2g-modal-container.show {\n",
       "    opacity: 1;\n",
       "}\n",
       "#m2g-modal-container.show #m2g-modal {\n",
       "    opacity: 1;\n",
       "    transform: translate(0, 0);\n",
       "}\n",
       "\n",
       "/* Header + close btn */\n",
       "#m2g-modal h2 {\n",
       "    line-height: 26px;\n",
       "    padding-right: 40px;\n",
       "    text-transform: capitalize;\n",
       "}\n",
       "#m2g-modal h3 {\n",
       "    \n",
       "}\n",
       "#m2g-modal button.close {\n",
       "    background: transparent;\n",
       "    padding: 0;\n",
       "    color: var(--m2g-black);\n",
       "    font-size: 1.5rem;\n",
       "    width: 40px;\n",
       "    height: 40px;\n",
       "    position: absolute;\n",
       "    top: 13px;\n",
       "    right: 13px;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#m2g-modal .svg-wrap svg {\n",
       "    max-width: 100%;\n",
       "    margin-bottom: 20px;\n",
       "}\n",
       "\n",
       "/* Separator */\n",
       "hr {\n",
       "    width: 100%;\n",
       "    height: 1px;\n",
       "    background: #ddd;\n",
       "    margin: 15px 0;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Hover states\n",
       " */\n",
       "@media (hover:hover) {\n",
       "    /* Pagination */\n",
       "    #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
       "        background: #f0f0f0;\n",
       "        z-index: 1;\n",
       "    }\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        /* Keeping the hover border consiistent */\n",
       "        margin-left: 1px;\n",
       "        border-left: none;\n",
       "        min-width: 40px;\n",
       "    }\n",
       "\n",
       "    /* Dropdowns &amp; search */\n",
       "    #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
       "        background-color: #f0f0f0;\n",
       "    }\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
       "        background: #fff;\n",
       "        border-color: rgba(0,0,0,.3);\n",
       "    }\n",
       "    /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
       "    #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
       "        background-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Search options */\n",
       "    #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
       "        background: rgba(0,0,0,.15);\n",
       "    }\n",
       "\n",
       "    /* Grid */\n",
       "    /* Note: this is in an ::after pseudo element, so the transparent\n",
       "    hover color plays nice with the cell background color. */\n",
       "    #mols2grid .m2g-cell:hover::after {\n",
       "        content: &#x27;&#x27;;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        background-color: rgba(0,0,0,0.05);\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    /* info button */\n",
       "    #mols2grid .m2g-info:hover::before {\n",
       "        content: &#x27;i&#x27;;\n",
       "        color: #fff;\n",
       "        width: 18px;\n",
       "        height: 18px;\n",
       "        line-height: 18px;\n",
       "        background: var(--m2g-hl);\n",
       "        position: absolute;\n",
       "        left: 5px;\n",
       "        top: 5px;\n",
       "        border-radius: 9px;\n",
       "    }\n",
       "    \n",
       "    /* Callback button */\n",
       "    #mols2grid .m2g-callback:hover::after {\n",
       "        background-color: var(--m2g-black);\n",
       "        background-image: var(--m2g-icn-triangle-white);\n",
       "        border-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Copyable text */\n",
       "    .copy-me:hover {\n",
       "        text-decoration: underline;\n",
       "        text-decoration-color: var(--m2g-blue);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Responsive behavior.\n",
       " * - - -\n",
       " * Note: container queries won&#x27;t work in older browsers,\n",
       " * but this is purely aesthetical behavior so that&#x27;s ok.\n",
       " * https://caniuse.com/css-container-queries\n",
       " */\n",
       "\n",
       "/* This sets the msg-list div as reference container */\n",
       "#mols2grid {\n",
       "    container-type: inline-size;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
       " * - - -\n",
       " * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
       " * Buffer required because the button width inside the search depends on the font.\n",
       " */\n",
       "@container (max-width: 870px) {\n",
       "    #mols2grid .m2g-functions {\n",
       "        flex-direction: column-reverse;\n",
       "        gap: 10px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:last-child {\n",
       "        justify-content: flex-end;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
       "        margin-right: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + sort on one row,\n",
       " * we reduce the sort drodpwon width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    #mols2grid .m2g-functions .m2g-sort {\n",
       "        width: 80px;\n",
       "        flex-basis: 80px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
       "        font-size: 0;\n",
       "        line-height: 0;\n",
       "        padding-right: 0;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
       "        content: &#x27;Sort&#x27;;\n",
       "        font-size: var(--m2g-fs);\n",
       "        line-height: var(--m2g-h);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
       " * we reduce the pagination width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    /* We&#x27;re overriding min-width from different\n",
       "    locations, including responsive rules */\n",
       "    #mols2grid ul.m2g-pagination li,\n",
       "    #mols2grid ul.m2g-pagination li:last-child,\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        min-width: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for searchbar + menu\n",
       " * we scale down the searchbar to fit the container.\n",
       " */\n",
       "@container (max-width: 370px) {\n",
       "    #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
       "        flex: 1;\n",
       "    }\n",
       "    #mols2grid .m2g-searchbar {\n",
       "        width: calc(100% - 50px);\n",
       "    }\n",
       "    #mols2grid .m2g-search-options {\n",
       "        width: 50px;\n",
       "    }\n",
       "\n",
       "    /* Collapse options in T/M buttons */\n",
       "    #mols2grid .m2g-search-options .m2g-option {\n",
       "        width: 25px;\n",
       "        text-align: center;\n",
       "        padding: 0;\n",
       "        overflow: hidden;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
       "        content: &#x27;T\\A&#x27;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
       "        content: &#x27;S\\A&#x27;\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
       "@container (min-width: 519px) and (max-width: 779px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 4);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
       "@container (min-width: 779px) and (max-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 6);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
       "@container (min-width: 1559px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 12);\n",
       "    }\n",
       "}\n",
       "\n",
       "            /* Custom CSS */\n",
       "            \n",
       "        &lt;/style&gt;\n",
       "        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "        &lt;script&gt;\n",
       "    // Set iframe height to fit content.\n",
       "    function fitIframe(iframe) {\n",
       "        // Ignore when there&#x27;s no iframe\n",
       "        if (!iframe) return\n",
       "\n",
       "        // Only fit height when no specific height was given.\n",
       "        if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
       "\n",
       "        // Initial fit + refit whenever the window width changes.\n",
       "        _fit()\n",
       "        $(window).on(&#x27;resize&#x27;, function() {\n",
       "            if (window.innerWidth != window.prevInnerWidth) {\n",
       "                window.prevInnerWidth = window.innerWidth\n",
       "                _fit();\n",
       "            }\n",
       "        })\n",
       "\n",
       "        // Fit iframe height to content height.\n",
       "        function _fit() {\n",
       "            var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
       "            iframe.style.height = height;\n",
       "        }\n",
       "    }\n",
       "&lt;/script&gt;\n",
       "\n",
       "&lt;!-- prettier-ignore --&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "        \n",
       "        &lt;!-- Custom header --&gt;\n",
       "        \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/head&gt;\n",
       "    &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
       "            &lt;!-- Pagination &amp; search --&gt;\n",
       "            &lt;div class=&quot;m2g-functions&quot;&gt;\n",
       "                \n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Pagination --&gt;\n",
       "                    &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
       "                    &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Sort dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;data-IC50-(nM)&quot;&gt;IC50-(nM)&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                            \n",
       "                            &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
       "                            \n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
       "                        &lt;div class=&quot;m2g-display&quot;&gt;\n",
       "                            Index\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Search bar --&gt;\n",
       "                    &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
       "                        &lt;input\n",
       "                            type=&quot;text&quot;\n",
       "                            class=&quot;m2g-searchbar form-control&quot;\n",
       "                            placeholder=&quot;Search&quot;\n",
       "                            aria-label=&quot;Search&quot;\n",
       "                            aria-describedby=&quot;basic-addon1&quot;\n",
       "                        /&gt;\n",
       "                        &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Action dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            &lt;option hidden&gt;-&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
       "                            &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
       "                            &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-icon&quot;&gt;\n",
       "                            &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
       "                                &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
       "                            &lt;/svg&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "\n",
       "            &lt;!-- Grid --&gt;\n",
       "            \n",
       "            &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-IC50-(nM) copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "        &lt;script&gt;\n",
       "            // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    listClass: &#x27;m2g-list&#x27;,\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-mols2grid-id&#x27;, &#x27;data-img&#x27;, &#x27;data-SMILES&#x27;, &#x27;data-IC50-(nM)&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-IC50-(nM) copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 24,\n",
       "    pagination: {\n",
       "        paginationClass: &quot;m2g-pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;mols2grid-id&quot;: 0, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2cn[nH]c2)c1&quot;, &quot;data-IC50-(nM)&quot;: 365.0, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;mols2grid-id&quot;: 1, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2cn[nH]c2)c1&quot;, &quot;data-IC50-(nM)&quot;: 30.0, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;mols2grid-id&quot;: 2, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1ccc2nnc(CC(=O)N(Cc3cccc(Cl)c3)c3ccc(cc3)-c3cn[nH]c3)n2c1&quot;, &quot;data-IC50-(nM)&quot;: 3365.0, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;mols2grid-id&quot;: 3, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2cnc3ccccn23)c2ccc(cc2)-c2cn[nH]c2)c1&quot;, &quot;data-IC50-(nM)&quot;: 1146.0, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;mols2grid-id&quot;: 4, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2cnccn2)c2ccc(cc2)-c2cn[nH]c2)c1&quot;, &quot;data-IC50-(nM)&quot;: 5217.0, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;mols2grid-id&quot;: 5, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2cccnn2)c2ccc(cc2)-c2cn[nH]c2)c1&quot;, &quot;data-IC50-(nM)&quot;: 5000.0, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;mols2grid-id&quot;: 6, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 71.0, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;mols2grid-id&quot;: 7, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1ccc2nnc(CC(=O)N(Cc3cc(F)cc(Cl)c3)c3ccc(cc3)-c3c[nH]cn3)n2c1&quot;, &quot;data-IC50-(nM)&quot;: 77.0, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;mols2grid-id&quot;: 8, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 65.0, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;mols2grid-id&quot;: 9, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 15.0, &quot;data-mols2grid-id-display&quot;: 9}, {&quot;mols2grid-id&quot;: 10, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;C[C@@H](N(C(=O)Cc1nnc2ccccn12)c1ccc(cc1)-c1c[nH]cn1)c1cc(F)cc(Cl)c1&quot;, &quot;data-IC50-(nM)&quot;: 587.0, &quot;data-mols2grid-id-display&quot;: 10}, {&quot;mols2grid-id&quot;: 11, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;C[C@@H](N(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1)c1cc(F)cc(Cl)c1&quot;, &quot;data-IC50-(nM)&quot;: 76.0, &quot;data-mols2grid-id-display&quot;: 11}, {&quot;mols2grid-id&quot;: 12, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1ccc(Cl)cc1CN(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 308.0, &quot;data-mols2grid-id-display&quot;: 12}, {&quot;mols2grid-id&quot;: 13, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1c(Cl)cccc1CN(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 370.0, &quot;data-mols2grid-id-display&quot;: 13}, {&quot;mols2grid-id&quot;: 14, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cncc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 101.0, &quot;data-mols2grid-id-display&quot;: 14}, {&quot;mols2grid-id&quot;: 15, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;COc1ccc(Cl)cc1CN(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 191.0, &quot;data-mols2grid-id-display&quot;: 15}, {&quot;mols2grid-id&quot;: 16, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;COc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 100.0, &quot;data-mols2grid-id-display&quot;: 16}, {&quot;mols2grid-id&quot;: 17, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1ccc(F)c(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 786.0, &quot;data-mols2grid-id-display&quot;: 17}, {&quot;mols2grid-id&quot;: 18, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1ccc(F)c(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 159.0, &quot;data-mols2grid-id-display&quot;: 18}, {&quot;mols2grid-id&quot;: 19, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cccc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1F&quot;, &quot;data-IC50-(nM)&quot;: 1297.0, &quot;data-mols2grid-id-display&quot;: 19}, {&quot;mols2grid-id&quot;: 20, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cccc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1F&quot;, &quot;data-IC50-(nM)&quot;: 184.0, &quot;data-mols2grid-id-display&quot;: 20}, {&quot;mols2grid-id&quot;: 21, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cccc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 351.0, &quot;data-mols2grid-id-display&quot;: 21}, {&quot;mols2grid-id&quot;: 22, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 209.0, &quot;data-mols2grid-id-display&quot;: 22}, {&quot;mols2grid-id&quot;: 23, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 53.0, &quot;data-mols2grid-id-display&quot;: 23}, {&quot;mols2grid-id&quot;: 24, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cn2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 40.0, &quot;data-mols2grid-id-display&quot;: 24}, {&quot;mols2grid-id&quot;: 25, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;CC(N(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1)c1cc(F)cc(F)c1&quot;, &quot;data-IC50-(nM)&quot;: 114.0, &quot;data-mols2grid-id-display&quot;: 25}, {&quot;mols2grid-id&quot;: 26, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cccnn2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 506.0, &quot;data-mols2grid-id-display&quot;: 26}, {&quot;mols2grid-id&quot;: 27, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)N2CCNCC2=O)c1&quot;, &quot;data-IC50-(nM)&quot;: 481.0, &quot;data-mols2grid-id-display&quot;: 27}, {&quot;mols2grid-id&quot;: 28, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)N2CCNC(=O)C2)c1&quot;, &quot;data-IC50-(nM)&quot;: 370.0, &quot;data-mols2grid-id-display&quot;: 28}, {&quot;mols2grid-id&quot;: 29, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C#N)c1&quot;, &quot;data-IC50-(nM)&quot;: 1249.0, &quot;data-mols2grid-id-display&quot;: 29}, {&quot;mols2grid-id&quot;: 30, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;FC(F)(F)c1cncc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 82.0, &quot;data-mols2grid-id-display&quot;: 30}, {&quot;mols2grid-id&quot;: 31, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 53.0, &quot;data-mols2grid-id-display&quot;: 31}, {&quot;mols2grid-id&quot;: 32, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1ccc2nnc(CC(=O)N(Cc3cc(F)cc(F)c3)c3ccc(cc3)-c3c[nH]cn3)n2n1&quot;, &quot;data-IC50-(nM)&quot;: 604.0, &quot;data-mols2grid-id-display&quot;: 32}, {&quot;mols2grid-id&quot;: 33, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1ccc2nnc(CC(=O)N(Cc3cc(F)cc(Cl)c3)c3ccc(cc3)-c3c[nH]cn3)n2n1&quot;, &quot;data-IC50-(nM)&quot;: 250.0, &quot;data-mols2grid-id-display&quot;: 33}, {&quot;mols2grid-id&quot;: 34, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cccnc2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 188.0, &quot;data-mols2grid-id-display&quot;: 34}, {&quot;mols2grid-id&quot;: 35, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Clc1cccc(CN(C(=O)Cc2cccnc2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 414.0, &quot;data-mols2grid-id-display&quot;: 35}, {&quot;mols2grid-id&quot;: 36, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;CC(C)(C)CN(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 356.0, &quot;data-mols2grid-id-display&quot;: 36}, {&quot;mols2grid-id&quot;: 37, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;CC(C)CN(C(=O)Cc1nnc2ccccn12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 8099.0, &quot;data-mols2grid-id-display&quot;: 37}, {&quot;mols2grid-id&quot;: 38, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cccc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 621.0, &quot;data-mols2grid-id-display&quot;: 38}, {&quot;mols2grid-id&quot;: 39, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncnc2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 542.0, &quot;data-mols2grid-id-display&quot;: 39}, {&quot;mols2grid-id&quot;: 40, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2noc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 839.0, &quot;data-mols2grid-id-display&quot;: 40}, {&quot;mols2grid-id&quot;: 41, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)CC2NC(=O)c3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 30840.0, &quot;data-mols2grid-id-display&quot;: 41}, {&quot;mols2grid-id&quot;: 42, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;NC(=O)c1ccc(cc1)N(Cc1cc(F)cc(F)c1)C(=O)Cc1cncc2ccccc12&quot;, &quot;data-IC50-(nM)&quot;: 100.0, &quot;data-mols2grid-id-display&quot;: 42}, {&quot;mols2grid-id&quot;: 43, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cccnn2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 389.0, &quot;data-mols2grid-id-display&quot;: 43}, {&quot;mols2grid-id&quot;: 44, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;COc1ccc(F)cc1CN(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 179.0, &quot;data-mols2grid-id-display&quot;: 44}, {&quot;mols2grid-id&quot;: 45, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;COc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 90.0, &quot;data-mols2grid-id-display&quot;: 45}, {&quot;mols2grid-id&quot;: 46, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cnccn2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 2038.0, &quot;data-mols2grid-id-display&quot;: 46}, {&quot;mols2grid-id&quot;: 47, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2=CCNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 139.0, &quot;data-mols2grid-id-display&quot;: 47}, {&quot;mols2grid-id&quot;: 48, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2=CCNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 81.0, &quot;data-mols2grid-id-display&quot;: 48}, {&quot;mols2grid-id&quot;: 49, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)ccc1Cl&quot;, &quot;data-IC50-(nM)&quot;: 1087.0, &quot;data-mols2grid-id-display&quot;: 49}, {&quot;mols2grid-id&quot;: 50, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)CC2C(=O)Nc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 6235.0, &quot;data-mols2grid-id-display&quot;: 50}, {&quot;mols2grid-id&quot;: 51, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 193.0, &quot;data-mols2grid-id-display&quot;: 51}, {&quot;mols2grid-id&quot;: 52, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)cc(OC(F)(F)F)c1&quot;, &quot;data-IC50-(nM)&quot;: 113.0, &quot;data-mols2grid-id-display&quot;: 52}, {&quot;mols2grid-id&quot;: 53, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 69.0, &quot;data-mols2grid-id-display&quot;: 53}, {&quot;mols2grid-id&quot;: 54, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;CC(C)(C)NC(=O)C(N(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)C1=CCNC1)c1cc(F)cc(F)c1&quot;, &quot;data-IC50-(nM)&quot;: 1027.0, &quot;data-mols2grid-id-display&quot;: 54}, {&quot;mols2grid-id&quot;: 55, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;CC(C)(C)NC(=O)C(N(C(=O)Cc1cncc2ccccc12)c1ccc(cc1)-c1c[nH]cn1)c1cc(F)cc(F)c1&quot;, &quot;data-IC50-(nM)&quot;: 231.0, &quot;data-mols2grid-id-display&quot;: 55}, {&quot;mols2grid-id&quot;: 56, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc(Br)c2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 187.0, &quot;data-mols2grid-id-display&quot;: 56}, {&quot;mols2grid-id&quot;: 57, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1cncc(CC(=O)N(Cc2cc(F)cc(F)c2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 103.0, &quot;data-mols2grid-id-display&quot;: 57}, {&quot;mols2grid-id&quot;: 58, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(F)cc(CN(C(=O)Cc2cncc(c2)C2CC2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 161.0, &quot;data-mols2grid-id-display&quot;: 58}, {&quot;mols2grid-id&quot;: 59, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2=CCNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 608.0, &quot;data-mols2grid-id-display&quot;: 59}, {&quot;mols2grid-id&quot;: 60, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CC(=O)N(Cc2cc(F)cc(Cl)c2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 220.0, &quot;data-mols2grid-id-display&quot;: 60}, {&quot;mols2grid-id&quot;: 61, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1cncc(CC(=O)N(Cc2cc(F)cc(Cl)c2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 84.0, &quot;data-mols2grid-id-display&quot;: 61}, {&quot;mols2grid-id&quot;: 62, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc(c2)C2CC2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 115.0, &quot;data-mols2grid-id-display&quot;: 62}, {&quot;mols2grid-id&quot;: 63, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 56.0, &quot;data-mols2grid-id-display&quot;: 63}, {&quot;mols2grid-id&quot;: 64, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2nncc3ccccc23)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 61.0, &quot;data-mols2grid-id-display&quot;: 64}, {&quot;mols2grid-id&quot;: 65, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;NCc1ccc(cc1)N(Cc1cc(F)cc(F)c1)C(=O)Cc1cncc2ccccc12&quot;, &quot;data-IC50-(nM)&quot;: 76.0, &quot;data-mols2grid-id-display&quot;: 65}, {&quot;mols2grid-id&quot;: 66, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cnccc2C(F)(F)F)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 1001.0, &quot;data-mols2grid-id-display&quot;: 66}, {&quot;mols2grid-id&quot;: 67, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cnccc2Cl)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 311.0, &quot;data-mols2grid-id-display&quot;: 67}, {&quot;mols2grid-id&quot;: 68, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1ccncc1CC(=O)N(Cc1cc(F)cc(Cl)c1)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 136.0, &quot;data-mols2grid-id-display&quot;: 68}, {&quot;mols2grid-id&quot;: 69, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;COc1ccncc1CC(=O)N(Cc1cc(F)cc(Cl)c1)c1ccc(cc1)-c1c[nH]cn1&quot;, &quot;data-IC50-(nM)&quot;: 222.0, &quot;data-mols2grid-id-display&quot;: 69}, {&quot;mols2grid-id&quot;: 70, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2cncc(c2)C2CC2)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 112.0, &quot;data-mols2grid-id-display&quot;: 70}, {&quot;mols2grid-id&quot;: 71, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Cc1cncc(CC(=O)N(Cc2cc(F)cc(Cl)c2)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 110.0, &quot;data-mols2grid-id-display&quot;: 71}, {&quot;mols2grid-id&quot;: 72, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CN(C(=O)Cc2cncc(F)c2)c2ccc(cc2)-c2c[nH]cn2)c1&quot;, &quot;data-IC50-(nM)&quot;: 1309.0, &quot;data-mols2grid-id-display&quot;: 72}, {&quot;mols2grid-id&quot;: 73, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cc(Cl)cc(CN(C(=O)Cc2nncc3ccccc23)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 70.0, &quot;data-mols2grid-id-display&quot;: 73}, {&quot;mols2grid-id&quot;: 74, &quot;data-img&quot;: null, &quot;data-SMILES&quot;: &quot;Fc1cncc(CN(C(=O)Cc2cncc(F)c2)c2ccc(cc2)C2CNC2)c1&quot;, &quot;data-IC50-(nM)&quot;: 5225.0, &quot;data-mols2grid-id-display&quot;: 74}]);\n",
       "\n",
       "\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i])\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i])\n",
       "        }\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &#x27;{&#x27;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
       "        content += &#x27;}&#x27;\n",
       "        return content\n",
       "    }\n",
       "    to_keys() {\n",
       "        var content = []\n",
       "        for (let [key] of this) {\n",
       "            content.push(key)\n",
       "        }\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName, allItems) {\n",
       "        var content = &#x27;&#x27;\n",
       "\n",
       "        if (allItems) {\n",
       "            // Gather all smiles\n",
       "            for (var item of allItems) {\n",
       "                var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
       "                var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
       "                content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
       "            }\n",
       "        } else {\n",
       "            // Gather selected smiles\n",
       "            for (let [key, value] of this) {\n",
       "                content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
       "            }\n",
       "        }\n",
       "\n",
       "        var a = document.createElement(&#x27;a&#x27;)\n",
       "        var file = new Blob([content], { type: &#x27;text/plain&#x27; })\n",
       "        a.href = URL.createObjectURL(file)\n",
       "        a.download = fileName\n",
       "        a.click()\n",
       "        a.remove()\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "function add_selection(grid_id, _id, smiles) {\n",
       "    SELECTION.multi_set(_id, smiles);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "function del_selection(grid_id, _id) {\n",
       "    SELECTION.multi_del(_id);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    var kernel_env = &quot;jupyter&quot;;\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    var kernel_env = &quot;colab&quot;;\n",
       "} else {\n",
       "    var kernel_env = null;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sortField = &#x27;mols2grid-id&#x27;\n",
       "var sortOrder = &#x27;asc&#x27;\n",
       "\n",
       "// Sort dropdown\n",
       "$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
       "\n",
       "// Sort order\n",
       "$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
       "\n",
       "function sort(e) {\n",
       "    if (e) {\n",
       "        sortField = e.target.value\n",
       "        var selectedOption = e.target.options[e.target.selectedIndex]\n",
       "        var sortFieldDisplay = selectedOption.text\n",
       "    }\n",
       "\n",
       "    // Sort\n",
       "    if (sortField == &#x27;checkbox&#x27;) {\n",
       "        listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
       "    } else {\n",
       "        listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
       "    }\n",
       "\n",
       "    // Update UI.\n",
       "    $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
       "}\n",
       "\n",
       "// prettier-ignore\n",
       "function flipSort() {\n",
       "    $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
       "    $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sort()\n",
       "}\n",
       "\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName]\n",
       "    var y = itemB.values()[options.valueName]\n",
       "    if (typeof x === &#x27;number&#x27;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y\n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1\n",
       "        }\n",
       "    } else {\n",
       "        x = x ? x.toLowerCase() : x\n",
       "        y = y ? y.toLowerCase() : y\n",
       "        return x &lt; y ? -1 : x &gt; y ? 1 : 0\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1\n",
       "            } else {\n",
       "                return 0\n",
       "            }\n",
       "        } else {\n",
       "            return -1\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1\n",
       "    } else {\n",
       "        return 0\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// grid interactions (select, click, tooltip, key events)\n",
       "// Check if selection UI is supported.\n",
       "var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
       "\n",
       "listObj.on(&quot;updated&quot;, initInteraction);\n",
       "\n",
       "// (Re)initialiuze all grid interaction every time the grid changes.\n",
       "function initInteraction(list) {\n",
       "    initCellClick()\n",
       "    initToolTip()\n",
       "    initKeyboard()\n",
       "    if (supportSelection) initCheckbox()\n",
       "\n",
       "\n",
       "    // Hide pagination if there is only one page.\n",
       "    if (listObj.matchingItems.length &lt;= listObj.page) {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
       "    }\n",
       "\n",
       "    // Add a bunch of phantom cells.\n",
       "    // These are used as filler to make sure that\n",
       "    // no grid cells need to be resized when there&#x27;s\n",
       "    // not enough results to fill the row.\n",
       "    $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
       "}\n",
       "\n",
       "// Cell click handler.\n",
       "function initCellClick() {\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
       "        if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
       "            // Info button / Checkbox --&gt; do nothing.\n",
       "        } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
       "            // Data string --&gt; copy text.\n",
       "            copyOnClick(e.target)\n",
       "        } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
       "            // Callback button.\n",
       "            onCallbackButtonClick(e.target)\n",
       "        } else {\n",
       "            // Outside checkbox --&gt; toggle the checkbox.\n",
       "            if (supportSelection) {\n",
       "                var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "                chkbox.checked = !chkbox.checked\n",
       "                $(chkbox).trigger(&#x27;change&#x27;)\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Store an element&#x27;s text content in the clipboard.\n",
       "function copyOnClick(target) {\n",
       "    var text = $(target).text()\n",
       "    navigator.clipboard.writeText(text)\n",
       "\n",
       "    // Blink the cell to indicate that the text was copied.\n",
       "    $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    setTimeout(function() {\n",
       "        $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    }, 450)\n",
       "}\n",
       "\n",
       "// Keyboard actions.\n",
       "function initKeyboard() {\n",
       "    // Disable scroll when pressing UP/DOWN arrows\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
       "        if (e.which == 38 || e.which == 40) {\n",
       "            e.preventDefault()\n",
       "        }\n",
       "    })\n",
       "\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
       "        var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "        if (e.which == 13) {\n",
       "            // ENTER: toggle\n",
       "            chkbox.checked = !chkbox.checked\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 27 || e.which == 8) {\n",
       "            // ESC/BACKSPACE: unselect\n",
       "            chkbox.checked = false\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 37) {\n",
       "            // LEFT\n",
       "            $(this).prev().focus()\n",
       "        } else if (e.which == 39) {\n",
       "            // RIGHT\n",
       "            $(this).next().focus()\n",
       "        } else if (e.which == 38 || e.which == 40) {\n",
       "            var containerWidth = $(this).parent().outerWidth()\n",
       "            var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
       "            var columns = Math.round(containerWidth / cellWidth)\n",
       "            var index = $(this).index()\n",
       "            if (e.which == 38) {\n",
       "                // UP\n",
       "                var indexAbove = Math.max(index - columns, 0)\n",
       "                $(this).parent().children().eq(indexAbove).focus()\n",
       "            } else if (e.which == 40) {\n",
       "                // DOWN    \n",
       "                var total = $(this).parent().children().length\n",
       "                var indexBelow = Math.min(index + columns, total)\n",
       "                $(this).parent().children().eq(indexBelow).focus()\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Show tooltip when hovering the info icon.\n",
       "function initToolTip() {\n",
       "    $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
       "        // Show on enter\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
       "            if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
       "                copyOnClick(e.target)\n",
       "            } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
       "                \n",
       "            }\n",
       "        })\n",
       "    }).mouseleave(function() {\n",
       "        // Hide on leave, unless sticky.\n",
       "        if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    }).click(function() {\n",
       "        // Toggle sticky on click.\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
       "\n",
       "        // Hide tooltip when sticky was turned off.\n",
       "        if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Update selection on checkbox click.\n",
       "function initCheckbox() {\n",
       "    $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&quot;.data-SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    });\n",
       "}\n",
       "\n",
       "// Callback button\n",
       "function onCallbackButtonClick(target) {\n",
       "    var data = {}\n",
       "    data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
       "                                            .attr(&quot;data-mols2grid-id&quot;));\n",
       "    data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
       "    $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
       "        let name = this.className.split(&quot; &quot;)\n",
       "            .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
       "            .substring(5);\n",
       "        data[name] = this.innerHTML;\n",
       "    });\n",
       "\n",
       "    \n",
       "    // Call custom js callback.\n",
       "    None\n",
       "    \n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Actions\n",
       " */\n",
       "\n",
       "// Listen to action dropdown.\n",
       "$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
       "    var val = e.target.value\n",
       "    switch(val) {\n",
       "        case &#x27;select-all&#x27;:\n",
       "            selectAll()\n",
       "            break\n",
       "        case &#x27;select-matching&#x27;:\n",
       "            selectMatching()\n",
       "            break\n",
       "        case &#x27;unselect-all&#x27;:\n",
       "            unselectAll()\n",
       "            break\n",
       "        case &#x27;invert&#x27;:\n",
       "            invertSelection()\n",
       "            break\n",
       "        case &#x27;copy&#x27;:\n",
       "            copy()\n",
       "            break\n",
       "        case &#x27;save-smiles&#x27;:\n",
       "            saveSmiles()\n",
       "            break\n",
       "        case &#x27;save-csv&#x27;:\n",
       "            saveCSV()\n",
       "            break\n",
       "    }\n",
       "    $(this).val(&#x27;&#x27;) // Reset dropdown\n",
       "})\n",
       "\n",
       "// Check all.\n",
       "function selectAll(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "\n",
       "// Check matching.\n",
       "function selectMatching(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.matchingItems.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "// Uncheck all.\n",
       "function unselectAll(e) {\n",
       "    var _id = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "};\n",
       "\n",
       "// Invert selection.\n",
       "function invertSelection(e) {\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "        } else {\n",
       "            item.show()\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "            item.hide()\n",
       "        }\n",
       "        if (chkbox.checked) {\n",
       "            _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "            _smiles.push(item.values()[&quot;data-SMILES&quot;]);\n",
       "        } else {\n",
       "            _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        }\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "};\n",
       "\n",
       "// Copy to clipboard.\n",
       "function copy(e) {\n",
       "    // navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "    content = _renderCSV(&#x27;\\t&#x27;)\n",
       "    navigator.clipboard.writeText(content)\n",
       "};\n",
       "\n",
       "// Export smiles.\n",
       "function saveSmiles(e) {\n",
       "    var fileName = &quot;selection.smi&quot;\n",
       "    if (SELECTION.size) {\n",
       "        // Download selected smiles\n",
       "        SELECTION.download_smi(fileName);\n",
       "    } else {\n",
       "        // Download all smiles\n",
       "        SELECTION.download_smi(fileName, listObj.items);\n",
       "    }\n",
       "};\n",
       "\n",
       "// Export CSV.\n",
       "function saveCSV(e) {\n",
       "    content = _renderCSV(&#x27;;&#x27;)\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "};\n",
       "\n",
       "// Render CSV for export of clipboard.\n",
       "function _renderCSV(sep) {\n",
       "    // Same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "        .map(elm =&gt; elm.classList[1])\n",
       "        .filter(name =&gt; name !== &quot;data-img&quot;);\n",
       "    // Remove &#x27;data-&#x27; and img\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // CSV content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    listObj.items.forEach(function (item) {\n",
       "        let data = item.values();\n",
       "        let index = data[&quot;mols2grid-id&quot;];\n",
       "        if (SELECTION.has(index) || SELECTION.size === 0) {\n",
       "            content += index;\n",
       "            columns.forEach((key) =&gt; {\n",
       "                content += sep + data[key];\n",
       "            })\n",
       "            content += &quot;\\n&quot;;\n",
       "        }\n",
       "    });\n",
       "    return content\n",
       "}\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;width&quot;: 130, &quot;height&quot;: 90};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // Searchbar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        listObj.items.forEach(function (item) {\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = mol.get_substruct_matches(qmol);\n",
       "                if (results === &quot;\\{\\}&quot;) {\n",
       "                    item.found = false;\n",
       "                } else {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    results = JSON.parse(results);\n",
       "                    \n",
       "                    var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
       "                    results.forEach(function (match) {\n",
       "                        highlights[&quot;atoms&quot;].push(...match.atoms)\n",
       "                        highlights[&quot;bonds&quot;].push(...match.bonds)\n",
       "                    });\n",
       "                    \n",
       "                    var index = item.values()[&quot;mols2grid-id&quot;];\n",
       "                    smarts_matches[index] = highlights;\n",
       "                    \n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        });\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "// Temporary fix for regex characters being escaped by list.js\n",
       "// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
       "// the string unmodified. Other calls should not be affected, unless they use the exact\n",
       "// same pattern and replacement value.\n",
       "// TODO: remove once the issue is fixed in list.js and released\n",
       "String.prototype.replace = (function(_super) {\n",
       "    return function() {\n",
       "        if (\n",
       "            (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
       "            &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
       "        ) {\n",
       "            if (this.length === 0) {\n",
       "                return &#x27;&#x27;\n",
       "            }\n",
       "            return this\n",
       "        }\n",
       "        return _super.apply(this, arguments);\n",
       "    };         \n",
       "})(String.prototype.replace);\n",
       "\n",
       "// Switch search type (Text or SMARTS)\n",
       "$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
       "    $(this).addClass(&quot;sel&quot;);\n",
       "});\n",
       "\n",
       "// Searchbar update event handler\n",
       "$(&#x27;#mols2grid .m2g-searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-IC50-(nM)&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // Generate images for the currently displayed molecules.\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles, index, template_mol) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[index];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "            mol.generate_aligned_coords(template_mol, true);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;130&quot; height=&quot;90&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 130 90&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "\n",
       "// Update images when the list is updated.\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var template_mol;\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "        template_mol = null;\n",
       "    } else {\n",
       "        template_mol = RDKit.get_qmol(query);\n",
       "        template_mol.set_new_coords(true);\n",
       "    }\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-SMILES&quot;).first().text();\n",
       "        var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
       "        var svg = draw_mol(smiles, index, template_mol);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "    if (template_mol) {\n",
       "        template_mol.delete();\n",
       "    }\n",
       "});\n",
       "    \n",
       "\n",
       "    // Trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    \n",
       "    // Set iframe height to fit content.\n",
       "    fitIframe(window.frameElement);\n",
       "});\n",
       "        &lt;/script&gt;\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/body&gt;\n",
       "&lt;/html&gt;\n",
       "\">\n",
       "</iframe>"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 45
  },
  {
   "cell_type": "markdown",
   "id": "089fcf8d-9533-4344-ae19-ae732cbd3a2a",
   "metadata": {},
   "source": [
    "### 3. Visualizing the Activity Distribution\n",
    "First, let's set some reasonable defaults for plots. "
   ]
  },
  {
   "cell_type": "code",
   "id": "495a6dfa-d9d6-46ad-8b53-f28be105c38e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.598180Z",
     "start_time": "2025-05-06T01:16:06.595988Z"
    }
   },
   "source": [
    "sns.set(rc={'figure.figsize': (5,5 )})\n",
    "sns.set_style('whitegrid')\n",
    "sns.set_context('notebook')"
   ],
   "outputs": [],
   "execution_count": 46
  },
  {
   "cell_type": "markdown",
   "id": "acb39da2-99ae-4484-bd2a-3e826ee4fd67",
   "metadata": {},
   "source": [
    "Let's look at the the IC50 distribution for the 75 compounds.  As we can see below, the default view isn't very helpful. "
   ]
  },
  {
   "cell_type": "code",
   "id": "0da4ac05-34e4-4166-b5d4-9d9e8c4fd0f4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.695757Z",
     "start_time": "2025-05-06T01:16:06.609280Z"
    }
   },
   "source": [
    "ax = sns.histplot(df[\"IC50 (nM)\"])"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ],
      "image/png": "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7FoAAAg6AV16HTFihB577DEdOXJEycnJp/2YqRtvvLGhtQEAYLmAgrLmTcnffPNNvfnmm7XW22w2ghIAEBICCspt27Y1dh0AAASlgIKye/fujV0HAABBKaCgfOGFF866zb//+78HMjQAAEGl0YOyTZs26ty5M0EJAAgJAQXlnj17ai0rKyvT7t27lZGRoUceeaTBhQEAEAwa7b3noqOjNXjwYN1333364x//2FjDAgBgqUZ/k9bzzz9f+/bta+xhAQCwRECXXk/HMAwdPHhQy5cv565YAEDICCgoe/XqJZvNdtp1hmFw6RUAEDICCsr77rvvtEHZpk0bDRs2TLGxsQ2tCwCAoBBQUKanpzd2HQAABKWAn6OsqKjQ+vXr9emnn6q0tFTt27dX//79NXr0aLVu3boxawQAwDIBBWVpaaluvfVW7dmzR926dVOnTp2Un5+vjRs36pVXXtGaNWvUtm3bxq4VAIBmF9DLQ5599lkVFhZq9erVev/997V27Vq9//77Wr16tYqLi7V48eLGrhMAAEsEFJTbtm3TtGnT1L9/f7/l/fv319SpU/Xee+81SnEAAFgtoKA8efKkLrzwwtOuu/DCC3Xs2LGG1AQAQNAIKCgvvvhi/e1vfzvtum3btumiiy5qUFEAAASLgG7mmTRpkh544AFVVFRo1KhROu+883T48GH99a9/1euvv66MjIxGLhMAAGsEFJQjRoyQ2+1WZmamXn/9dd/yVq1a6b777tO4ceMarUAAAKwUUFCWlZVpypQpGj9+vD7//HOVlJTo4MGDGjdunNq1a9fYNQIAYJl6PUeZm5urG2+8UStXrpQkxcTEaMiQIRoyZIgWLVqkm2++ud6fHHLs2DE9+uijGjJkiPr166ebbrpJu3bt8jvm+PHj1adPHw0bNkxZWVn1Gh8AgIaoc1B+++23mjhxokpKShQfH++3zuFwaPbs2Tp58qRuvvlmFRYW1rmABx54QF988YUWLlyoN954Q5dffrkmTZqkffv26ejRo7r99tsVGxur7Oxspaena/HixcrOzq57hwAANECdL70uW7ZM7du312uvvaZzzz3Xb53T6dT48eN13XXX6V//9V+VmZlZpxt6CgoK9Mknn+jVV19Vv379JElz5szR9u3btXHjRkVFRcnhcCgjI0ORkZGKi4tTQUGBli9frjFjxtSrUQAAAlHnGeWOHTt055131grJn+rYsaNuv/127dixo05jtm/fXsuWLVPv3r19y2w2mwzDUElJiXbt2qWUlBRFRv6Y5wMGDFB+fr6Ki4vrWjoAAAGr84zy+++/r9PrIxMSEup86TUmJkZDhw71W7Zp0ybt379fgwYN0nPPPaeEhAS/9Z07d5YkHThwQB07dqxj9f4Mw1BZWVlA+0qS1+uVJFVXVauqukoej0eGYQQ8XjDyeDx+30NROPQohUef9BgamrNHwzDO+LnKP1fnoOzQoYOKiorOut2RI0dMZ51mdu/erdmzZ+vqq69WamqqnnzySTkcDr9taj6ZpCasAlFZWanc3NyA96+pqby8XOUem1wulyoqKgIeL5i53W6rS2hy4dCjFB590mNoaK4ef54vZ1LnoExJSdH69et1/fXXm2735ptv6tJLL63rsD5bt27Vgw8+qOTkZC1cuFCSFBUVVSuAagIyOjq63seo0apVq1o3JNXHqRqOKCoqSlFOp+Lj40NyRul2uxUbGyun02l1OU0iHHqUwqNPegwNzdmjy+Wq87Z1DsoJEybopptu0oIFC3T//ffX+szJiooKPffcc/roo4+0bNmyulcrafXq1XriiSc0fPhwPfPMM76U79q1a61ZbM3PXbp0qdcxfspmszUoaGum6/YIuyLsESH7oJVO3ajVkN9VSxAOPUrh0Sc9hobm6LGul12legRlYmKiZs2apfnz5+utt97SlVdeqQsuuEBVVVU6cOCAPv30Ux09elS///3vNXjw4DoXsGbNGs2bN08TJkzQ7NmzZbf/eH9RSkqKXnvtNVVVVSkiIkLSqZuKevToEfDzkwAA1Ee93pnnlltuUa9evZSVlaVt27b5LoOec845GjRokO644w4lJyfXebz8/HzNnz9fw4cP1z333ON3J2tUVJTGjBmjFStWaM6cObrzzjv1j3/8Q6tWrdLcuXPrUzYAAAGr91vY/eIXv9AvfvELSdLRo0dlt9sDftu6zZs3q7KyUlu2bNGWLVv81o0ePVoLFizQihUr9MQTT2j06NHq1KmTZsyYodGjRwd0PAAA6iug93qt0b59+wYdfPLkyZo8ebLpNklJSVq7dm2DjgMAQKAC+jxKAADCBUEJAIAJghIAABMEJQAAJghKAABMEJQAAJggKAEAMEFQAgBggqAEAMAEQQkAgAmCEgAAEwQlAAAm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t695rrOmBiDYEJSARS655BINGTJEy5Yt07fffltr/YoVK3T48GHdeOONkqQdO3bo4Ycf9gvB6upqbd68WcnJyXI4HLrooot04YUXavPmzX5jbd68WbGxsb5Z7M916dJFERERvudNG+K6665TaWmpXnzxRZWUlJzxZqUaNcfs1q1bg48NNAVeRwlYaO7cubrttts0duxY3XrrrerTp49OnjypzZs3a+PGjRo7dqxGjRolSbrpppu0du1aTZ48Wenp6XI6nXrllVeUl5en//iP//CNOWXKFM2aNUvnnnuuUlNT9f7772vTpk167rnnzlhHdHS0+vXrp7///e+aOHFig3q68MILlZiYqBUrVmj48OG+G4nOZPfu3brgggt8s2Eg2BCUgIW6deumtWvXatWqVXr77be1fPlytWrVShdffLGefvppv8uWnTt31po1a7Rw4UI9/vjjOnnypBITE7Vy5Ur169fPt91vf/tbVVRU6C9/+Yuys7N14YUX6qmnntKIESNMa0lLS9Pzzz8vr9er1q1bN6ivESNGKCcn56yXXaVTL5O59tprG3Q8oCnZjJrb4QCENY/Ho1//+td66KGHfJd7m9pnn32mO++8U1u3buWdeRC0eI4SgKRTd5+mp6crKyurzi9Zaajly5frtttuIyQR1AhKAD6/+93v1LVr13p9ekigPvroIxUWFio9Pb3JjwU0BJdeAQAwwYwSAAATBCUAACYISgAATBCUAACYICgBADBBUAIAYIKgBADABEEJAICJ/wOyy1AMEfdg/wAAAABJRU5ErkJggg=="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 47
  },
  {
   "cell_type": "markdown",
   "id": "a015dbab-c887-4aa1-bc16-b3f54d31cf31",
   "metadata": {},
   "source": [
    "It's oftent easier to look at the distribution of **pIC50** values, where pIC50 is the negative log of the IC50. "
   ]
  },
  {
   "cell_type": "code",
   "id": "0c25bede-fc06-4737-8c7f-af0454aaea30",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.708821Z",
     "start_time": "2025-05-06T01:16:06.706703Z"
    }
   },
   "source": [
    "df[\"pIC50\"] = -np.log10(df[\"IC50 (nM)\"] * 1e-9)"
   ],
   "outputs": [],
   "execution_count": 48
  },
  {
   "cell_type": "code",
   "id": "9ef18725-ca13-45d0-84a1-4bef43ccb6f8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.771159Z",
     "start_time": "2025-05-06T01:16:06.719349Z"
    }
   },
   "source": [
    "ax = sns.histplot(df.pIC50)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ],
      "image/png": "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6lRdf/31/u9zcnI0bdo0vfHGGxo6dKi++OILzZ8/Xx06dLCkJgAATiXsw8Ivv/yyWrdurTfffFOtWrUKuM3hcGjEiBH6z//8T11//fWaP39+RBc1zZgxI2js4osv1vLly+u0zJAhQzRkyJA6/3wAAKwQ9p7runXrdNtttwUF64nOOOMMjRkzRuvWrbOiNgAAElLY4bpv376w/n81MzPTssPCAAAkorDDNS0tLehfXEIpKyurde8WAIDGLuxwzcrK0ooVK045b+XKlbrwwgujKgoAgEQWdriOHDlS69ev14wZM0K+lGBlZaVmzpypTz/9VDfffLOlRQIAkEjCvlq4W7duevTRRzVt2jS988476tOnj9q1ayev16tdu3Zp/fr1OnjwoO677z5dccUV9VkzAABxrU6v0HTzzTerc+fOWrRokdasWePfg23atKlycnJ06623Br1tHAAAp5s6v/zhpZde6n8pwYMHD8pms1n6kocAACS6iF5buEbr1q2tqgMAgEYjft6DCgCARoJwBQDAYoQrAAAWI1wBALAY4QoAgMUIVwAALEa4AgBgMcIVAACLEa4AAFiMcAUAwGKEKwAAFiNcAQCwGOEKAIDFCFcAACxGuAIAYDHCFQAAixGuAABYjHAFAMBihCsAABYjXAEAsBjhCgCAxQhXAAAsRrgCAGAxwhUAAIsRrgAAWKxJrAs4lfXr1+uWW24JeVu7du20Zs2aoPE//vGPeuSRR4LGP/74Y51//vmW1wgAwIniPlx79Oihzz77LGCsqKhId9xxh8aNGxdymcLCQvXq1UuzZs0KGE9LS6u3OgEAqBH34ZqSkqL09HT/91VVVZo+fboGDhyoG264IeQyRUVF6ty5c8ByAAA0lIQ75/r73/9epaWlevTRR086p7CwUB07dmzAqgAA+Le433M9UUVFhebPn69Ro0apTZs2IeeUlZVp//792rhxo1577TUdOnRI3bt318SJE5WRkRHxzzZNUy6XK6Jl3W53wOfGgJ7in2EYcjgckiSf1xfjagJ5VV2Pz/TJ6/PWefmafuqjr2hri1Q4PcWqtnB4zera3G63TNP0f33i50RnmqYMwwhrbkKF6zvvvKOKigqNHDnypHOKiookSUlJSZo5c6ZcLpfmzZun4cOH67333tOZZ54Z0c+uqqpSQUFBRMvWKCkpiWr5eERP8cvhcKhLly6SJI/HE+NqAlV6KiVVP2F2lUf2pFWqn76sqi1StfUU69pq42lWHSfbt28PCtPG8jclVZ+qDEdChevKlSs1cOBAtW7d+qRzsrOztWHDBrVs2dI/NnfuXPXv318rVqzQHXfcEdHPTk5OjvhQs9vtVklJidq3b+/fk0h09BT/TnyGbbfbZUuKn7NAKfbqB6jU1FQ5mzrrvLzP65PH46mXvqKtLVLh9BSr2sJhd9glSRkZGQF7ro3pb6q4uDjsuQkTrmVlZdq8ebPuvPPOU849MVglyel0ql27dtqzZ0/EP98wDDmd0d2ZHQ5H1OuIN/SUGGxJNiXZkmJdhl/Svy73sBnR1VUffVlVW6Rq6ynWtdUmyaiuLVSINpa/qXAPCUsJdEHTl19+KcMw1KtXr1rnLVu2TL179w44tHLs2DGVlJRwkRMAoEEkTLhu3bpV5557btCzIq/Xq3379vnDtH///jJNU5MmTdJ3332nLVu2KC8vT2lpaRo6dGgsSgcAnGYSJlz379+vVq1aBY2XlpYqJydHH374oSTp7LPP1tKlS1VeXq5hw4Zp9OjRat68uV599VXZ7fYGrhoAcDpKmHOuU6ZMCTnerl07FRYWBoxdeOGFWrRoUQNUBQBAsITZcwUAIFEQrgAAWIxwBQDAYoQrAAAWI1wBALAY4QoAgMUIVwAALEa4AgBgMcIVAACLEa4AAFiMcAUAwGKEKwAAFiNcAQCwGOEKAIDFCFcAACxGuAIAYDHCFQAAixGuAABYjHAFAMBihCsAABYjXIEo+XxmrEuolWHEugLg9NMk1gUAic5mM7R8VZH2HXTFupQAmee11sDs82WQrkCDI1wBC+w76NKu/eWxLiNAeitHrEsATlscFgYAwGKEKwAAFiNcAQCwGOEKAIDFCFcAACxGuAIAYDHCFQAAixGuAABYjHAFAMBihCsAABYjXAEAsFhChOvOnTvVqVOnoI+33nor5PyDBw/qwQcfVFZWlrKysvT444/L5YqvF1UHADReCfHC/YWFhUpNTdXq1asD3uGjefPmIeffe++9qqio0JIlS3TkyBFNnjxZTz31lGbOnNlQJQMATmMJEa5FRUXKyMhQmzZtTjl38+bN2rBhgz788EN16NBBkvTrX/9at912mx544AGdddZZ9V0uAOA0lxCHhQsLC9WxY8ew5ubn5ys9Pd0frJLUq1cvGYahTZs21VeJAAD4Jcyea3p6uoYPH66SkhKdf/75uvvuu3XFFVcEzd2zZ4/OPvvsgLGUlBS1atVKpaWlEddgmmbE523dbnfA58aAnqoZhiGHwyGv6ZPX562v0iLilc//tc/rq2Vmw6upzRfh762mn/roK9raIhVOT7GqLRxes7o2t9st0zT9X5/4OdGZphlwarI2cR+ulZWVKikpkcPh0KRJk+R0OvXuu+/q9ttv1+LFi9WnT5+A+W63WykpKUHrSU1NVUVFRcR1VFVVqaCgIOLlJamkpCSq5ePR6d6Tw+FQly5d5HF75CqPr4vmKj2V/q89Hk8MKwlWU1tFRUVUv7f66Muq2iJVW0+xrq02nmbVcbJ9+/agMG1MjxOh8iWUuA/XlJQUbdy4UU2aNPE3ddFFF2nbtm1atGhRULja7XZVVlYGraeiokJOpzPiOpKTk8M+NP1jbrdbJSUlat++vRwOR8Q1xBN6qlbzLNbusMvZ9Hh9lldnKfZ/PwjY7XbZkuLnLFBNbampqXI2rfvfpc/rk8fjqZe+oq0tUuH0FKvawmF32CVJGRkZAXuujelxori4OOy5cR+ukkKGYmZmpj777LOg8bZt22r16tUBY5WVlTp06FBUFzMZhhFVOEvVeznRriPe0FO1JMOmJFtSPVUUmaQTLqmwJcVXfTW12aL8vdVHX1bVFqnaeop1bbVJMqprCxWijeVxItxDwlICXNC0detW9ejRQ/n5+QHjf//730PuSWZlZWn37t3asWOHf2z9+vWSpJ49e9ZvsQAAKAHCNTMzUxdccIGeeuop5efna9u2bZo+fbr+9re/ady4cfJ6vdq3b5//PEX37t3Vs2dP3X///fr666/1xRdf6Mknn9SQIUP4NxwAQIOI+3C12WyaP3++unXrpgkTJmjo0KH66quvtHjxYnXq1EmlpaXKycnRhx9+KKl6t/3FF19Uu3btNGrUKE2YMEF9+/bVlClTYtsIAOC0kRDnXNPS0jRt2rSQt7Vr106FhYUBY2eccYbmzJnTEKUBABAk7vdcAQBINIQrAAAWI1wBALAY4QoAgMUIVwAALEa4AgBgMcIVAACLEa4AAFiMcAUAwGKEKwAAFiNcgX8xDEMOh6NObysFAKEkxGsL4/Tm85my2eo/8BwOh7p06VLvPwdA40e4Iu7ZbIaWryrSvoOuev05XtMnj9sju8Puf+PnU8k8r7UGZp9fr3UBSDyEKxLCvoMu7dpfXq8/w+vzylXukrPpcSXZksJaJr2Vo15rApCYOOcKAIDFCFcAACxGuAIAYDHCFQAAixGuAABYjHAFAMBihCsAABYjXAEAsBjhCgCAxQhXAAAsRrgCAGAxwhUAAIsRrgAAWIxwBQDAYoQrAAAWI1wBALAY4QoAgMUIVwAALEa4AgBgMcIVAACLxX24Hjp0SE888YT69u2rnj17atiwYcrPzz/p/D/+8Y/q1KlT0MeOHTsasGoAwOmsSawLOJUHHnhABw4c0KxZs5SWlqZly5Zp7NixWrFihTp06BA0v7CwUL169dKsWbMCxtPS0hqqZADAaS6u91x37Nihzz//XE8++aQuu+wy/eQnP9HkyZN11lln6f333w+5TFFRkTp37qz09PSAj6SkpAauHgBwuorrPdfWrVvr5Zdf1kUXXeQfMwxDpmnq8OHDIZcpLCzUoEGDLK/FNE25XK6IlnW73QGfG4OG6skwDDkcDnlNn7w+b73+LJ/XF/A5HF79a5kGqK+uamqT6tZTQ4j29xbJtgpXrLZpOD3F9f3NrK7N7XbLNE3/1yd+TnSmacowjLDmxnW4tmjRQldeeWXA2EcffaTvv/9eOTk5QfPLysq0f/9+bdy4Ua+99poOHTqk7t27a+LEicrIyIiqlqqqKhUUFES1jpKSkqiWj0f13ZPD4VCXLl3kcXvkKo/syU1deTyesOdWeiolSRUVFQ1WX7hqapPq1lNDsOr3Vh99xXqb1tZTrGurjadZdZxs3749KEwb02NfSkpKWPPiOlx/bNOmTXrsscd01VVXKTc3N+j2oqIiSVJSUpJmzpwpl8ulefPmafjw4Xrvvfd05plnRvyzk5OT1bFjx4iWdbvdKikpUfv27eVwOCKuIZ40VE81zxLtDrucTY/X28+RqvcYPB6P7Ha7bEnhnTFJsVf/oaWmpsrZ1Fmf5dVZTW2S6tRTQ4j29xbJtmqo2iIVTk/xfH+zO+ySpIyMjIA918b02FdcXBz23IQJ19WrV2vixInq3r170MVKNbKzs7Vhwwa1bNnSPzZ37lz1799fK1as0B133BHxzzcMQ05ndHdmh8MR9TriTUP1lGTYlGRrmPPmtqTwf1bSvy5bsDVgfeFKOuGSirr01BCs+r3VR1+x3qa19RTr2mqTZFTXFipEG8tjX7iHhKU4v6Cpxuuvv668vDz17dtXCxYskN1uP+ncE4NVkpxOp9q1a6c9e/bUd5kAAEhKgHBdtmyZfvOb3+jmm2/W888/X+vx7mXLlql3794B5yyOHTumkpKSiA/pAgBQV3Edrtu3b9e0adM0YMAA3XnnnTpw4ID27dunffv26ejRo/J6vdq3b58/TPv37y/TNDVp0iR999132rJli/Ly8pSWlqahQ4fGuBsAwOkirsP1z3/+s6qqqrRq1Srl5OQEfEydOlWlpaXKycnRhx9+KEk6++yztXTpUpWXl2vYsGEaPXq0mjdvrldffbXWQ8kAAFgpri9oGjdunMaNG1frnMLCwoDvL7zwQi1atKg+ywIAoFZxvecKAEAiIlwRkZpXTqrLpekATi+n8+NEXB8WRsPx+UzZbOH/AdS8chIASFIzZ3LQ40g8PU7U9TEuWoQrJEk2m6Hlq4q072B4L6nmNX3yuD2yO+z+fx6vD5nntdbA7PPrbf0ArOFIaRL0ONJQjxOnkt7aqZsGZDbozyRc4bfvoEu79peHNdfr88pV7pKz6fF6faWY9FaJ/5JpwOnkxMeRhnqciEeccwUAwGKEKwAAFiNcAQCwGOEKAIDFCFcAACxGuAIAYDHCFQAAixGuAABYjHAFAMBihCsAABYjXAEAsBjhCgCAxQhXAAAsRrgCAGAxwrUBGUbDvVEvACB2CNcGkpycrNRUe6zLAAA0AN4svYE0adJENpuh5auKtO+gK9blBMg8r7UGZp8f6zIAoNEgXBvYvoMu7dpfHusyAqS3csS6BABoVDgsDACAxQhXAAAsRrgCAGAxwhUAAIsRrgAAWIxwBQDAYoQrAAAWI1wBALAY4QoAgMUIVwAALJYQ4erz+TRnzhxdccUV6t69u2699Vbt2LHjpPMPHjyoBx98UFlZWcrKytLjjz8ulyu+Xs8XANB4JUS4zps3T2+++aZ++9vfavny5TIMQ7fffrsqKytDzr/33nv1ww8/aMmSJZozZ44+//xzPfXUUw1cNQDgdBX34VpZWalXXnlFeXl5uvLKK9W5c2c999xz2rNnj1atWhU0f/PmzdqwYYOmT5+url27qk+fPvr1r3+td955R3v27IlBBwCA003ch+vWrVtVXl6u7Oxs/1iLFi3UpUsXbdy4MWh+fn6+0tPT1aFDB/9Yr169ZBiGNm3a1CA1AwBOb3H/lnO7d++WJJ199tkB423atFFpaWnQ/D179gTNTUlJUatWrULOD0dVVZVM09TXX38d0fKmacrr9WrLli26tL1PPc6LrzdNT27i0pYtW3RZe5+8YdZmmqZMOWVIMgwjrmqLVCQ9NWR9dVVTW06nFHl9yfW6neoq2t9bfd7/YrVNw+kpEe5vJ9bWUI8Tp2Kz+bRlyxaZphnVeqqqqsLuI+7D1e12S6oOyBOlpqbq8OHDIef/eG7N/IqKiohqqPllRnrnMAxDNlv1QYJmjuSI1tEQmlJbxOK5vmbO4L+HeBHPvzdqi0w81xZtwBuG0XjC1W6vfgZUWVnp/1qSKioq5HAEv8m33W4PeaFTRUWFnE5nRDX06NEjouUAAKenuD/nWnOId+/evQHje/fuVdu2bYPmt23bNmhuZWWlDh06pLPOOqv+CgUA4F/iPlw7d+6sZs2aaf369f6xI0eO6Ntvv9Vll10WND8rK0u7d+8O+D/YmmV79uxZ/wUDAE57cX9YOCUlRSNGjNAzzzyjtLQ0nXPOOfqf//kftW3bVgMGDJDX61VZWZmaN28uu92u7t27q2fPnrr//vs1ZcoUuVwuPfnkkxoyZAh7rgCABmGY0V4+1QC8Xq9mzZqlFStWyOPxKCsrS0888YTatWunf/7zn7rqqqs0ffp0/fKXv5QkHThwQE899ZQ+/fRTpaam6uc//7keffRRpaamxrgTAMDpICHCFQCARBL351wBAEg0hCsAABYjXAEAsBjhCgCAxQhXAAAsRrgCAGAxwhUAAIsRrhbbvn27evTooRUrVpx0zh//+Ed16tQp6OPEl2yMtZ07d4as8a233go5/+DBg3rwwQeVlZWlrKwsPf7443K5XA1cde3q2lMibCdJWrlypQYPHqxu3brp6quv1kcffXTSuYmwnWrUpa9431br168PWV+nTp101VVXhVwm3rdVJD3F+3ayUty//GEiqaqq0sSJE0/5B1BYWKhevXpp1qxZAeNpaWn1WV6dFBYWKjU1VatXrw54i6XmzZuHnH/vvfeqoqJCS5Ys0ZEjRzR58mQ99dRTmjlzZkOVfEp17SkRttM777yjxx57TA8//LD69eun999/Xw888IDatm0b8t2cEmE7SXXvK963VY8ePfTZZ58FjBUVFemOO+7QuHHjQi4T79sqkp7ifTtZyoRlnn32WXPkyJFmZmam+fbbb5903pgxY8zf/va3DVhZ3b300kvmL37xi7Dmfvnll2ZmZqZZXFzsH/v000/NTp06mbt3766vEuusLj2ZZvxvJ5/PZ/bv39+cMWNGwPitt95qzp8/P2h+omynuvZlmvG/rX6ssrLSvPrqq80JEyaEvD1RttWJTtWTaSbedooGh4UtsnHjRi1fvjysZ5WFhYXq2LFjA1QVubrUmJ+fr/T0dHXo0ME/1qtXLxmGoU2bNtVXiXVW1997vG+nf/zjH9q5c6euvfbagPFFixbpzjvvDJqfKNuprn1J8b+tfuz3v/+9SktL9eijj4a8PVG21YlO1ZOUeNspGoSrBY4cOaJJkybpV7/6lf/9Z0+mrKxM+/fv18aNG3XNNdcoJydH48eP1/bt2xuo2vAUFRXpwIEDGj58uH76059q2LBh+vTTT0PO3bNnT1DfKSkpatWqlUpLSxui3LDUpadE2E4lJSWSJJfLpbFjx6pPnz664YYbtHbt2pDzE2U71bWvRNhWJ6qoqND8+fM1atQotWnTJuScRNlWNcLpKdG2U7QIVwtMmTJFl1xySdAz7VCKiookSUlJSZo5c6aee+45uVwuDR8+XPv376/vUsNSWVmpkpISHTt2TBMmTNDLL7+sbt266fbbb9e6deuC5rvdbqWkpASNp6amqqKioiFKPqW69pQI2+nYsWOSpIcffljXXHONXnnlFV1++eW6++67E3Y7SXXvKxG21YneeecdVVRUaOTIkSedkyjbqkY4PSXadooWFzRFaeXKlcrPz9d7770X1vzs7Gxt2LBBLVu29I/NnTtX/fv314oVK3THHXfUV6lhS0lJ0caNG9WkSRP/H/hFF12kbdu2adGiRerTp0/AfLvdrsrKyqD1VFRUyOl0NkjNp1LXnhJhOyUnJ0uSxo4dq6FDh0qSLrzwQn377bdavHhxQm4nqe59JcK2OtHKlSs1cOBAtW7d+qRzEmVb1Qinp0TbTtFizzVKb7/9tg4cOKB+/fqpR48e/isZn3zySV199dUhlznxziVJTqdT7dq10549e+q93nA5nc6gZ86ZmZkha2zbtq327t0bMFZZWalDhw7F1RvU16UnKf63U9u2bSVV93Cijh076p///GfI+YmwneralxT/26pGWVmZNm/erMGDB9c6L1G2lRR+T1LibCcrEK5ReuaZZ/Thhx9q5cqV/g+p+jL6l19+OWj+smXL1Lt3b3k8Hv/YsWPHVFJSEjcn+rdu3aoePXooPz8/YPzvf/97yBqzsrK0e/fugP9VW79+vSSpZ8+e9VtsmOraUyJspy5duqhp06b66quvAsaLiop03nnnBc1PhO0k1b2vRNhWNb788ksZhqFevXrVOi9RtpUUfk+JtJ0sEevLlRujE/8V5/jx4+bevXtNt9ttmqZp7tq1y8zKyjLz8vLMoqIi8+uvvzZHjx5t/uxnP/PPiTWv12vecMMN5jXXXGNu3LjRLC4uNqdNm2ZedNFF5tatW4N68vl85n//93+bQ4cONb/66itz3bp1Zv/+/c1HHnkkxp38W117SoTtZJqmOXfuXLNHjx7me++9Z+7YscOcN2+e2blzZ/OLL75IyO1Uoy59Jcq2Mk3TfOGFF8yBAwcGjSfytgq3p0TaTlYgXOvBieH6ww8/BP3f67fffmveeuut5qWXXmr27NnTzMvLM3ft2hWrckM6cOCA+eijj5qXX3652a1bN/Omm24yN27caJpm6J72799v5uXlmZdcconZu3dv88knnzQ9Hk+syg+prj0lwnYyTdN85ZVXzNzcXLNr167mL37xC3PVqlWmaSbudqpRl74SZVs9+eST5o033hg0nsjbqi49Jcp2soJhmqYZ671nAAAaE865AgBgMcIVAACLEa4AAFiMcAUAwGKEKwAAFiNcAQCwGOEKAIDFCFcAACxGuAKnofXr16tTp07+16s90Z///GeNHTtWP/3pT3XJJZfommuu0dy5c/1vBVdj27Zt6tSpU9DHz3/+84B5X3/9tUaMGKEePXro8ssv18yZM0O+4wvQmPCWcwAkST6fTw899JD+9Kc/6brrrtOwYcP8L6C/aNEirVq1SkuXLvW/s8nWrVslSa+++qpSU1P967Hb7f6vv//+e40ZM0Y9evTQ888/r23btum5557T0aNH9dvf/rZhGwQaEOEKQJK0cOFCvf/++3rxxRc1YMAA/3ifPn2UnZ2tYcOG6YUXXtCvfvUrSVJBQYHOOecc9e7du9Z1Nm3aVPPmzVNKSoquvPJK2e12/eY3v9Fdd92lc845p977AmKBw8JAI5Sbm6vnnntO06dPV69evdSrVy899NBDOnjwYMj5VVVVeuWVV9S3b9+AYK1xySWXaMKECbrgggv8YwUFBbrwwgtrreOzzz5Tv379At5H9+c//7l8Pp8+++yzCLsD4h97rkAjtWzZMp1//vmaNm2aysrK9Oyzz+of//iH3nrrraC533zzjQ4ePKj+/fufdH133nlnwPdbt25Vhw4ddNNNN+nbb79VixYtNHToUN13331KTk6Wx+PRzp07lZGREbBcWlqamjVrppKSEkv6BOIR4Qo0UoZhaPHixWrevLmk6lAbP368PvnkEzkcjoC5u3fvliS1a9curHXv379f+/fvl2EYmjhxov7jP/5D69at04IFC1RaWqpnn31WR44ckSQ1a9YsaPmmTZsGXSAFNCaEK9BI9e/f3x+sUvWh4uTkZOXn5+uKK64ImGuzVZ8h8vl8Ya27WbNmWrx4sTIyMnT22WdLknr16qWUlBQ9//zzuvvuu0OGag3TNGUYRl1bAhIG51yBRqpNmzYB39tsNrVq1cq/R3mimguLdu7cedL1lZWVqaKiQlL1FcE//elP/cFao1+/fpKqDxnXBHt5eXnQulwuV0DwA40N4Qo0UocOHQr43uv16uDBg0pLSwuae+GFF+rMM8/UJ598ctL1TZkyRVdccYU8Ho/+8Y9/6I033gg6tOvxeCRJrVu3ltPp1FlnnaUdO3YEzCkrK9OxY8fUsWPHCDsD4h/hCjRSn376acCLNaxZs0bHjx9Xnz59gubabDaNHj1af/3rX7VmzZqg2zdu3Ki1a9dq0KBBstvt2rNnj6ZMmaI//elPAfM+/PBDNW3aVF27dpUkXX755frrX/8aUMef/vQnJSUlKTs726pWgbjDOVegkdq9e7fuuusu3XLLLSotLdWsWbOUk5Oj3r17h3xlptGjR2vjxo269957dcMNN6hfv36y2WzKz8/Xa6+9pgsuuEAPP/ywJPn/vWfGjBlyu936yU9+or/+9a967bXXNGnSJP8LTdx222364IMPdNttt2nMmDEqKSnRrFmzdNNNNwUdUgYaE8M0TTPWRQCwVm5urnr06KEWLVpo5cqVcjqduuaaa3T//ffLbrdr/fr1uuWWW/Tqq68GvAjE8ePHtXz5cr3zzjvasWOHKisr1a5dO1199dUaOXKkmjZt6p979OhRvfDCC1q9erX27dun8847T6NGjdKNN94YUEt+fr6efvppFRQUqHXr1vqv//ov3XfffWrShOf2aLwIV6ARys3N9e9ZAmh4nHMFAMBihCsAABbjsDAAABZjzxUAAIsRrgAAWIxwBQDAYoQrAAAWI1wBALAY4QoAgMUIVwAALEa4AgBgsf8H8joRVgZ5Ko4AAAAASUVORK5CYII="
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 49
  },
  {
   "cell_type": "markdown",
   "id": "f95c4b6b-1689-43f5-94b6-aa8cc1334d6e",
   "metadata": {},
   "source": [
    "For visualization it's often helpful to bin the activity into high, medium, and low bins.  Here well put compounds with 6 < pIC50 < 7 (0.1-1$\\micro$M) into the \"medium\" bin, and compounds with pIC50 > 7 into the \"high\" bin. "
   ]
  },
  {
   "cell_type": "code",
   "id": "373692a1-9967-475c-a6ab-0c2fbfd1de73",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.785243Z",
     "start_time": "2025-05-06T01:16:06.782766Z"
    }
   },
   "source": [
    "df[\"activity\"] = pd.cut(df.pIC50,bins=[0,6,7,100],labels=[\"low\",\"med\",\"high\"],right=False)"
   ],
   "outputs": [],
   "execution_count": 50
  },
  {
   "cell_type": "code",
   "id": "fdfeaacd-eda9-42a5-a696-132641fc50eb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.858813Z",
     "start_time": "2025-05-06T01:16:06.796278Z"
    }
   },
   "source": [
    "ax = sns.histplot(x=\"pIC50\",hue=\"activity\",data=df,bins=np.arange(4,9,0.5))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ],
      "image/png": "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SnXp0kVt2rSxO9LPYuoVAFDuzpw5o0WLFqlWrVp69tln7Y5jiSNKAEC5+7npYSfiiBIAAAsUJQAAFihKAAAsUJQAAFigKAEAsEBRAgBggaIEABRRnAujVxWMBAA4nGma5bq/oKAgeTweBQUFBbTv2NhYrVix4jIkswcXHAAAhzMMQ59/fUTnMnPKZX+maSrf61XN6h51a/+rctmnk1GUAFABnMvM0ZmM8inKgoIC5efny/3jBdGrOqZeAQCX1aZNm3TbbbcpLi5O3bp104wZM5STc7H0Bw4cqKefftq37rp16xQbG6vVq1f7lj3//PMaPHhwuecuRFECAC6bdevW6b777lP37t21fPlyPfXUU/roo49897mMj4/Xli1bfOtv3bpVhmHo3//+t2/ZJ598ol69epV79kJMvQIALpvXX39dvXv31tixYyVJV111lUzT1H333aeUlBT17NlTr7zyio4ePar69evr888/V+/evZWUlCRJ+v7777V//379z//8j22vgSNKAMBls2/fPl1zzTV+yzp16iRJ2rt3r9q0aaO6detqy5YtOn78uA4dOqTRo0fr4MGDOnr0qD755BM1a9ZMjRs3tiO+JI4oAQCXkWmaMgzDb5nX65Ukud0XK6hHjx7asmWLgoKC1KZNG7Vu3VoNGjRQUlKSNm3aZOvRpMQRJQDgMmrevLl27Njht2z79u2SpKZNm0qSevXqpa1bt2rLli3q0qWLJKlLly7atGmTkpKSbH1/UqIoAQCX0ciRI/Wvf/1L8+bNU2pqqjZu3KinnnpKPXv29BVlly5dlJOTozVr1viKsmvXrlqzZo2qV6+utm3b2vkSmHoFgIqgerXQcttX4QUHoqqFlHpbN954o7xer15//XW99tprqlmzphISEjR+/HjfOqGhobr22mu1efNm3/uZXbt2lWmaio+PLzJ1W94oSgBwONM0dW27K23bd0mLau/evX5fJyQkKCEhwfI58+bN8/v6iiuuUHJycon2e7kw9QoADlfeR1Rer1fZ2dnyer22H805AUUJACiioKDA7giOQVECAGCBogQAwAJFCQCABYoSAAALFCUAABYoSgAALFCUAABYoCgBAEW4XNRDIUYCABzONM1y3V9QUJA8Ho+CgoLKfd8lMXToUD366KOXfT9c6xUAHM4wDGUm/1verPRy2Z9ZUCCv16uQyBqK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hoZKknJycgLebl5envbs2VOqbJKUlpZW6m1UVYxdyXg8HkVHRysjI0MXzpy0O46fKE9NRUvKyMhQ5klnZatWO1iSdD4rSz84LJsRWSBJSk1NdWwhVfbv0//ul5/j6KIMCwtTbm6u37LCggwPDw94u8HBwWrWrFnAz8/OzlZaWpqaNGkij8cT8HaqIsYuMIXfB5GRkarmdtbRR2hUlKSL2cJU2+Y0/lw//pyICA/XFbWdlS3aU12SFBMT48gjysr+fbp///5ir+vooqxXr55OnDjht6zw67p16wa8XcMwSlW0hTweT5lspypi7EqmcIooyO2WERxscxp/QUFBF/92uyWHZdOP2VxBQQp2WLbCcy+cXESV+fu0uNOukgNO5rHSqVMn7dixQ94f3wORpK1btyomJibg9ycBACgJRxfloEGDlJmZqSlTpmj//v1asWKFlixZonvvvdfuaACAKsLRRVmrVi29+eabSk1N1cCBA/XKK6/okUce0cCBA+2OBgCoIhz1HuWMGTOKLGvXrp2WLVtmQxoAABx+RAkAgN0oSgAALFCUAABYoCgBALBAUQIAYIGiBADAAkUJAIAFihIAAAsUJQAAFihKAAAsUJQAAFigKAEAsEBRAgBggaIEAMACRQkAgAWKEgAACxQlAAAWKEoAACxQlAAAWKAoAQCwQFECAGCBogQAwAJFCQCABYoSqAAMw7A7AlBlUZTAT5imaXeESwoLC5NpmnKFhNkdBahy3HYHAJzEMAx9/vURncvMsTuKnwiPWzfENZThDpEzqxyovChK4L+cy8zRmQxnFWV+fr7dEYAqi6lXAAAsUJQAAFigKAEAsEBRAgBggaIEAMACRQkAgAWKEgAACxQlAAAWKEoAACxQlAAAWKAoAQCwQFECAGCBogQAwAJFCQCABYoSAAALFCUAABYoSgAALFCUAABYoCgBALBAUQIAYIGiBADAAkUJAIAFihIAAAsUJQAAFihKAAAsUJQAAFigKAEAsEBRotwFBwfLMAy7YwBAsbjtDoCqxTAMtW7dWkFBQXZHAYBioShR7oKCgrT5y+90Pjvf7ih+rqxdTe2vrm13DAAOQ1HCFucyLigj22t3DD9RESF2RwDgQLxHCQCABYoSAAALFCUAABYoSgAALFCUAABYoCgBALBAUQIAYKFCfI7y8OHDio+PL7L86aef1q233mpD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/PcWGxurXr162R3P0fLy8jRnzhz16NFDcXFxGjx4sL744gu7Y9mqQlyZx2ny8vL00EMPKSsry+4oFcbevXsVGhqqdevW+d3aJjIy0sZUzvf+++9r8uTJmjRpknr06KFVq1bpwQcfVL169bgTjoW4uDh99tlnfsv27dune+65R6NHj7YpVcXw2muvafny5ZoxY4YaNmyo+fPna9SoUfrwww9Vt25du+PZgqIMwMsvv6yICGfdaNXp9u3bp5iYGNWpU8fuKBWGaZp68cUXddddd+muu+6SJI0dO1ZffPGF/vOf/1CUFkJCQlS7dm3f13l5eXr22WfVp08f3XrrrTYmc77169crISFB3bp1kyQ9+uijevfdd7Vz50717dvX5nT2oChLaNu2bVq2bJlWrlypHj162B2nwti7d6+aNWtmd4wK5cCBAzp8+LBuvvlmv+ULFiywKVHF9de//lVHjx7VwoUL7Y7ieNHR0dq4caOGDBmi+vXra9myZQoJCVHLli3tjmYb3qMsgfT0dD3yyCP605/+5LtPJopn3759OnXqlAYPHqxrr71Wd9xxhz799FO7YzlaWlqaJCkrK0sjR45U165ddeutt2rDhg32BqtgcnJylJiYqLvuuosZjWKYMmWK3G63evXqpbZt22rOnDmaO3euGjVqZHc021CUJTBt2jR16NChyG/4sJabm6u0tDRlZmZqwoQJeuONN9S2bVuNGjVKW7dutTueY2VmZkqSJk2apISEBC1cuFDXXXedxowZw7iVwPvvv6+cnBwNHTrU7igVQkpKiqKiojRv3jwtW7ZMv/3tbzVp0iQlJyfbHc02TL0W08qVK7V9+3Z98MEHdkepcEJCQrRt2za53W7frdHatGmjlJQULViwQF27drU5oTMFBwdLkkaOHKmBAwdKklq2bKndu3dr0aJFjFsxrVy5Un369FGNGjXsjuJ4hw8f1sMPP6zFixerY8eOkqS2bdtq//79evnllzVv3jybE9qDI8piWr58uU6dOuU7ZbrwRIqpU6fqpptusjmd84WHhxe5f2jz5s11/PhxmxI5X7169SRdHKefatasmb7//ns7IlU4p0+f1pdffqn+/fvbHaVC+Prrr5WXl6e2bdv6LW/fvr3vrYCqiCPKYpo5c6YuXLjgt6xPnz4aP34834S/IDk5WXfccYfmz5/v+y1Vkr755htO8LHQqlUrRURE6KuvvvIbt3379lXp94tK4osvvpBhGOrcubPdUSqEwnMv9u7dq3bt2vmW79u3T40bN7Yrlu0oymL6uc8P1apVSw0aNCjnNBVL8+bNdfXVV+vPf/6zpk6dqho1aujvf/+7du7cqffee8/ueI4VFhamu+++W/PmzVPdunXVrl07rV69Wlu2bNHixYvtjlchJCcnq2HDhvJ4PHZHqRDatWunjh07atKkSZo6darq1aunlStXauvWrVq6dKnd8WxDUeKyc7lcSkxM1MyZMzVhwgSlp6erVatWWrRokWJjY+2O52hjxoyRx+PRnDlzdPz4cTVt2lQvv/yyfvOb39gdrUL44YcfFB0dbXeMCsPlcunVV1/V3Llz9dhjj+ncuXNq3ry5Fi9erA4dOtgdzzaGaZqm3SEAAHAqTuYBAMACRQkAgAWKEgAACxQlAAAWKEoAACxQlAAAWKAoAQCwQFECFVxSUpJiY2OVlJRU5LE1a9Zo5MiRuvbaa9WhQwclJCRo3rx5vjuTFEpJSVFsbGyRP/369fNb7+uvv9aQIUMUFxen6667Ts8995xyc3Mv6+sD7MaVeYBKqKCgQA8//LA+/vhjDRo0SHfccYfvurELFizQ2rVrtWTJElWvXl2SfLdQ+stf/qLQ0FDfdsLCwnz/fejQIY0YMUJxcXGaO3euUlJSNGfOHGVkZOjpp58u3xcIlCOKEqiE3nzzTa1atUqvvPKKevfu7VvetWtXdenSRXfccYdefvll/elPf5Ik7dmzRw0aNLC8NN6bb76piIgIvfrqqwoJCVH37t0VFhamp556Svfddx/XPEalxdQr4HDx8fGaM2eOnn32WXXu3FmdO3fWww8/rDNnzlxy/by8PC1cuFA33HCDX0kW6tChgyZMmKCrr77at2zPnj1q2bKlZY7PPvtMPXr08LtdWr9+/VRQUKDPPvsswFcHOB9HlEAFsHTpUjVu3FjTp0/X6dOnNWvWLB04cEDvvvtukXW//fZbnTlzRj179vzZ7d17771+XycnJ6tp06a6/fbbtXv3bkVFRWngwIG6//77FRwcrAsXLujw4cOKiYnxe17NmjVVrVq1Kn2vQlR+FCVQARiGoUWLFikyMlLSxYIaO3asNm/eXOQWUseOHZMk/epXvyrWtn/44Qf98MMPMgxDDz30kK688kpt3bpV8+fP19GjRzVr1iylp6dLkqpVq1bk+REREUVODgIqE4oSqAB69uzpK0np4nRscHCwtm/fruuvv95vXZfr4jsqBQUFxdp2tWrVtGjRIsXExPhu3Nu5c2eFhIRo7ty5GjNmzCULspBpmjIMo6QvCagweI8SqADq1Knj97XL5VJ0dLTvSO+nCk+qOXz48M9u7/Tp08rJyZF08czWa6+91leShXr06CHp4rRsYUmfP3++yLaysrL8ShyobChKoAI4e/as39der1dnzpxRzZo1i6zbsmVLXXHFFdq8efPPbm/atGm6/vrrdeHCBR04cEDvvPNOkenTCxcuSJJq1Kih8PBw1a1bVwcPHvRb5/Tp08rMzFSzZs0CfGWA81GUQAXw6aef+n2wf/369crPz1fXrl2LrOtyuTR8+HBt2rRJ69evL/L4tm3btGHDBvXt21dhYWE6fvy4pk2bpo8//thvvQ8//FARERFq3bq1JOm6667Tpk2b/HJ8/PHHCgoKUpcuXcrqpQKOw3uUQAVw7Ngx3XfffRo2bJiOHj2q2bNnq1u3bvrNb35zySvyDB8+XNu2bdP48eN16623qkePHnK5XNq+fbveeustXX311Zo0aZIk+T5yMmPGDGVnZ+uqq67Spk2b9NZbb+mRRx7xXZTg7rvv1urVq3X33XdrxIgRSktL0+zZs3X77bcXmbYFKhPDNE3T7hAAfl58fLzi4uIUFRWllStXKjw8XAkJCXrggQcUFhampKQkDRs2TH/5y1/8LhiQn5+vZcuW6f3339fBgweVm5urX/3qV7rppps0dOhQRURE+NbNyMjQyy+/rHXr1unkyZNq1KiR7rrrLt12221+WbZv367nn39ee/bsUY0aNXTLLbfo/vvvl9vN79yovChKwOHi4+N9R3wAyh/vUQIAYIGiBADAAlOvAABY4IgSAAALFCUAABYoSgAALFCUAABYoCgBALBAUQIAYIGiBADAAkUJAIAFihIAAAv/DwnOVpvPGbMwAAAAAElFTkSuQmCC"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 51
  },
  {
   "cell_type": "markdown",
   "id": "9c434866-16a5-4dd0-b552-6261a0c5e5cf",
   "metadata": {},
   "source": [
    "Now that we have the IC50 data binned into high, med, low, we can use these categories to make plots showing mulitple parameters.  In the cells below we'll make a scatterplot of molecular weight (MW) vs LogP, a measure of lipophilicity. We can then color the plot by activty and see whether acitivity is driven by MW or LogP. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32cc014f-2aaa-409d-8d77-d53fc8c0bd1b",
   "metadata": {},
   "source": [
    "To calculate MW and LogP we need to add an RDKit molecule column to the dataframe.  As we will see in next couple of cells, the Pandas [apply](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.apply.html) method provides a handy way of performing operations on an entire dataframe column. "
   ]
  },
  {
   "cell_type": "code",
   "id": "b7c5c839-5b35-4d7b-8be9-4f41188f3fe3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.877921Z",
     "start_time": "2025-05-06T01:16:06.870133Z"
    }
   },
   "source": [
    "df['mol'] = df.SMILES.apply(Chem.MolFromSmiles)"
   ],
   "outputs": [],
   "execution_count": 52
  },
  {
   "cell_type": "markdown",
   "id": "e163ae3b-33f8-4e9c-83fb-0372d09a5bf0",
   "metadata": {},
   "source": [
    "Now that the dataframe has a **mol** column with the RDKit molecules, we can use **apply** to calculate MW and LogP. "
   ]
  },
  {
   "cell_type": "code",
   "id": "60f097aa-6514-4a11-99ad-cc1a47602664",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.901886Z",
     "start_time": "2025-05-06T01:16:06.888105Z"
    }
   },
   "source": [
    "df['MW'] = df.mol.apply(uru.MolWt)\n",
    "df['LogP'] = df.mol.apply(uru.MolLogP)"
   ],
   "outputs": [],
   "execution_count": 53
  },
  {
   "cell_type": "markdown",
   "id": "8f527494-8f27-4b2d-bea6-f0d46c07ad23",
   "metadata": {},
   "source": [
    "Use [seaborn](https://seaborn.pydata.org/) to make the scatterplot of MW vs LogP, colored by **activity**. Note that while we don't have a clear relationship between either MW or LogP and activity, the smallest molecules tend to have low to medium activity. "
   ]
  },
  {
   "cell_type": "code",
   "id": "8364dc9c-c962-49f9-a490-5d906eb80cf9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.970761Z",
     "start_time": "2025-05-06T01:16:06.912183Z"
    }
   },
   "source": [
    "ax = sns.scatterplot(x=\"MW\",y=\"LogP\",hue=\"activity\",data=df)\n",
    "sns.move_legend(ax, \"upper left\", bbox_to_anchor=(1, 1))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 500x500 with 1 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 54
  },
  {
   "cell_type": "markdown",
   "id": "020a2131-68f8-4aa4-860f-864b6ade6332",
   "metadata": {},
   "source": [
    "### 4. Understanding the Chemistry in the Downloaded Molecules \n",
    "We downloaded 75 molecules from BindingDB.  It can often be challenging to understand the trends in sets of molecules. In the next section, we'll look at how Cheminformatics tools can aid or exploratory data analysis. As a first step in this analysis, we will see which parts are common to all 75 of the molecules.  To do this, we can use the Maxiumum Common Substructure (MCS) capability in the RDKit.  To use this capability, we must first convert the SMILES in our dataframe to RDKit molecule objects.  As above, we can use the Pandas apply method to do this. "
   ]
  },
  {
   "cell_type": "code",
   "id": "fcfd8760-75ae-4952-8801-e0359c484ab3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:06.989559Z",
     "start_time": "2025-05-06T01:16:06.981879Z"
    }
   },
   "source": [
    "df['mol'] = df[\"SMILES\"].apply(Chem.MolFromSmiles)"
   ],
   "outputs": [],
   "execution_count": 55
  },
  {
   "cell_type": "markdown",
   "id": "d2f843a7-96ca-4638-83bb-b8dd57ba0555",
   "metadata": {},
   "source": [
    "Next we can calculate the MCS. "
   ]
  },
  {
   "cell_type": "code",
   "id": "4ddce7d8-916d-4c7a-ba44-573fdc3a6914",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.018084Z",
     "start_time": "2025-05-06T01:16:06.999960Z"
    }
   },
   "source": [
    "mcs = rdFMCS.FindMCS(df.mol)"
   ],
   "outputs": [],
   "execution_count": 56
  },
  {
   "cell_type": "markdown",
   "id": "232fbe8d-aaed-4aae-9e76-e24687994fb0",
   "metadata": {},
   "source": [
    "To visualize the MCS, we have to convert it to an RDKit molecule object. "
   ]
  },
  {
   "cell_type": "code",
   "id": "7aafa405-9ade-48d7-bcb1-a7d3d6138ed4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.035928Z",
     "start_time": "2025-05-06T01:16:07.029143Z"
    }
   },
   "source": [
    "pat = Chem.MolFromSmarts(mcs.smartsString)\n",
    "pat"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<rdkit.Chem.rdchem.Mol at 0x38d706a40>"
      ],
      "image/png": "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"
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 57
  },
  {
   "cell_type": "markdown",
   "id": "e6cb0bbd-5629-45b2-8762-970b255b6596",
   "metadata": {},
   "source": [
    "The visualization above can be difficult to interpret.  The MCS tends to make more sense when we map it onto the molecules. Here we can map the MCS on to the first molecule in the dataframe and display it as a red highlight. Note how we use the utilitiy function [rd_set_image_size](https://useful-rdkit-utils.readthedocs.io/en/latest/jupyter.html#useful_rdkit_utils.jupyter_utils.rd_set_image_size) from [useful_rdkit_utils](https://useful-rdkit-utils.readthedocs.io/en/latest/index.html) to set the image size. "
   ]
  },
  {
   "cell_type": "code",
   "id": "6695d3a5-9567-4048-9cdd-351d5b213a26",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.055517Z",
     "start_time": "2025-05-06T01:16:07.046828Z"
    }
   },
   "source": [
    "uru.rd_set_image_size(300,300)\n",
    "df.mol.values[0].GetSubstructMatch(pat)\n",
    "df.mol.values[0]"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<rdkit.Chem.rdchem.Mol at 0x38d101460>"
      ],
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAIAAAD2HxkiAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOydZ1gUVxuGn9lK77B0kV4XFWPFDlbECqIoRmNPYqIx0RQjmqZ+Rk0xRqOJDY1gQ2woltgbvQlKEZCl975lvh8DK6ImoFsU5r78sTs7zHkP8uxpbyFIkgQNDY3yYCjbABqarg4tQhoaJUOLkIZGydAipKFRMrQIaWiUDC1CGholQ4uQhkbJ0CKkoVEytAhpaJQMLUIaGiVDi5CGRsnQIqShUTK0CGlolAwtQhoaJUOLkIZGydAipKFRMrQIaWiUDC1CGholQ4uQhkbJ0CKkoVEytAhpaJQMLUIaGiVDi5CGRsnQIqShUTK0CGlolAwtQhoaJUOLkIZGydAipKFRMrQIaWiUDC1CGholQ4uQhkbJ0CKkoVEytAhpaJQMLcIXs24dEhKevj13Drt3K88amk4NLcIXc+QIHj9++jY2FhcvKs8amk4NLUIaGiXDUrYBby6VlSgqan5dW6tUU2g6NQRJksq24U2Ez0dZGdTVm9+WlcHbGwcPKtUmmk4KPR19Kdu3Iy2t+d/y5cq2hqbzQouQhkbJ0CKkoVEy9MbMixk5EqamT986OT1dH9LQyBZ6JHwxzs6IjX36lsOBjY3yrKHp1NAifDGhoVi4EHfuNL+9fBmXLyvVIJrOCy3ClzJ+PBYtgkikbDtoOju0CF+Kvz+0tPDLL8q2g6azQ2/M/Bs//YRhwzB1qrLtoOnU0CPhUxoacPQoJk9GXl7zlR49EBSEzz5Tqlk0nR16JIREgps3ERaGgwdRUgIA/fs//fSbb+DoCGtr9OunLANpOjldWoTJyQgLw759yMpqvuLsjKAgzJz5NHBJSwubNiEwkBYhjbzoFCIUChEdjfh4lJeDwYChIXr3hqsrCOKFtz9+/PjkSc6OHSbJyc1XbGwwYwYCA+Hg0HylZ08YGze/njEDV67Azk7e3aDporz9URQFBThwAE1NEAqfXuRwoKODWbOgoSG9VlFRcfLkyf3791+8eLF//19u3nxfVxc+PggKwogRLxPsM/zxB0QiLF4sh17QdGHe8o2Zigrs2ZOSne29e/fdJ0+oa3VCofeuXfUCAXbvhlBYX18fGho6YcIEHo83e/bsqKgoVVVVe/vUU6dQWIh9++Dl1S4F3r2LhQvx8ce4fVu+faLparzl09HwcDQ1VTQ0/PP48cKIiHsLFrAYDJFEEpWZKRSJolNS9k+c+Pf161VVVQCYTObAgQODgoKmT5+uqanZ0ab69MHHH2PLFvj5ISYGhoZy6A5Nl+RtFmFFBfLyQJIArHV1DdTUfrlzZ1nLzuajsrJBO3dSr52dnYOCgmbPnm0sXee9Ehs34v59XLuGgACcPw8m8zU7QEMDvN3T0dxcMJ7av2X06G+uXs2rqqLe2uvr+7m4BHt5pd+6lZycvHLlytdUIAAWC6GhMDHBpUtYu/Y1H0ZD08zbLML6ekgk0neuRkbv9ujx0dmz0iuhfn5rvLzsTExk2KaxMQ4eBIuFb79FeLgMH0zTdXmbRaih0WZGuHbo0Nt5eVGZmU8vicWtN0hlwtChWLcOJIk5c54eMNLQvDJvswi7dYNY3PqCJpe7edSolRcuPL3EYkFPT+Ytr1qFSZNQXo7Jk1FfL/PH03Qt3mYRqqvD3r7NYDjN1dVWqjoOBwMHtuv8oYMQBP78EzY2iIujc0DRvC5vswgBjBsHVVUzbe35vXpJr/0yduxKT08OhwNDw2fcQGWKjg7CwqCigpSUbQcOhMipFZquwNvvMVNVhZAQKk3v1tu3G0Wij/v147JYoUVFF5ua/AMCRowYIb/GQ0Iuzpzppaamdvv2bTc3N/k1RNOJectHQgBaWpg3j3r53dWrq6KiqpuaANwHdu7aFRMTI9fGAwNHzJ07t66ubsqUKZWVlXJti6az8vaLEACr2eWAy2IBaBSJnr5ubJR349u2bevVq9fDhw9nz5791k8raJRBpxAhQVCn9lwmE0ADJUI2GwoRoYqKytGjR/X09MLDw7ds2SLv5mg6H51ChGgeDJtHP7FY+rqhoUEBjVtZWe3du5cgiJUrV167dk0BLdJ0JjqLCJlMACrKmI5S+Pj4fPrppyKRyN/fXyAQKKZRms5BZxEhNRIymWgZCVUUNR2V8v3333t5eRUUFMyYMUNEZ0qkaTedS4StR0JKkAoUIZPJPHDggKmp6ZUrV5bTR/g07aaziJDJRJuNGeq1/NeE6enpJ06coF7zeDxqcbh9+3bFLEdpOgGdRYQv2ZiR90goFotnz549adKk3bt3U1dOnjxJkiRBEAxGZ/nd0siZzvKH8tzGjIpCpqMbNmy4ffu2mZnZ5MmTAcTFxe3YsYMgiM2bN3M4HLk2TdNp6CwifG5jRgFrwvj4+LVr1xIEsWvXLl1d3cbGxqCgoKampqVLl37wwQfya5emk9G5RKjAjRmp5N5///3Ro0cDWL16dWJiooODww8//CCnRmk6JZ1FhK02ZppHQgYD8tyYWbNmTUJCgo2NDSW5mzdvbt68mcVi7d27V1VVVU6N0nRKOosIW42EDfIfCW/durVp0yYGg7Fnzx4NDY3a2tp3331XLBavWrWqb9++8miRphPTWUTYeiSkNmYYDMhHhHV1dVLJeXp6Avjkk08ePnzYo0eP1atXy7w5mk5PZxHh80cUchPhihUr0tPT3d3d16xZA+DChQs7d+7kcrn79u2jd0RpXoFOJcJnfEcJAnJYE0ZFRf3+++9SyVVUVLz33nskSX7zzTd0UC/Nq9FZRPj8xoxEAlmPhJWVlZTk1q5dy+fzASxZsiQ3N3fAgAG0nxrNK9MpRFhSgrg4PHtEoZKbC1mL8IMPPsjJyenfv/+KFSsAnDhx4tChQ+rq6nv27GHS6bhpXpW3OQ0+RWkpdu1CYyPa+I4SBGQqwvDw8AMHDqipqVGSKy4uXrhwIYBNmzbZ0WXTaF6Dt1+EoaFoaqJett6YIQgizN9fhcsls7MJK6vXbEQquf/973/29vYAFi1aVFRU5O3tTV2noXll3vLpaE4OKiqkyfBbb8wAmOrs7GNjQ1y58vrtLF68uLCw0MvLa/HixQB279597NgxHR2d3bt3E3LIa0rTpXjLRZiRAaFQmt63uLYWQIxAIGlVowKPHyMsDPHxeNWd0j179hw9elRbW5uSXHZ2NrUNs23bNgsLi9ftAk2X5y2fjlZUoFWCM3U2G0Bmebnexo2+Dg7j7e1H2thoq6ggJQUpKSAIGBvD3h4ODjA2bmdm7ry8PEpyv/76q6WlpUQimTt3blVV1cSJE2fMmCGnbtF0Kd7y5L+Rkbhzp7UOZxw9GpacLGoZCbks1uBu3cbZ2Y2zt7dtXZRCRwc2NrC2hq0tXn7CTpLkmDFjIiMjJ0yYQEXubt26ddmyZYaGhklJSUZGRvLqF01X4i0X4YMHOHECz22BZpaXR6SlnUpP/+fxY2FL0RhrXV0va2sfe/tRtrYc6YkCiwVLS9jbw9ER2tptnvPzpk0fffqpoY5O4sGDPFfXBzU1vTw86uvrjx49SgUQ0tC8Pm+5CMVibN6MurqXfV5WX38xMzMqMzM8La2wpoa6qM7hDLOyGu/gMM7OzkxL6+ndurqwt4e9PaysIBbj7Nmfdu5cGRn5t5/fRBcXEUF47tx55/HjuXPnSuPoaWhen7dchAAyMnD4MITCf79LLJHEFRREpKefSk+Pyc+X9tnZ0HC8g4OPvf0ACwuGdJWoqgqJBEIhJJK8qipzLS0A6/75Z83ly+ba2olnzugMGCC/DtF0Nd5+EQJITkZ4OMTi1oV7weHA1BSensjKQno6ioulnzyuqIjMyIjKzDz78GFNyxmjobr6aFvbp3s5zxIrEPTbtUskkUQFBQ2zt8eiRfIoe0jTNekUIgRQVYWbN5Gairo6MJkwNkb//nBweHpDWRnS05GejpwcaWnReqHwRm5uRFraiQcPclrKubAYjL7m5uPt7cc7ODgbGgJoFIne+eOPxMLCj/v12zJ6NBgMODlh6lSFd5Kmc9JZRNh+hMLmsTE9HdXV0ssJhYWn09NPP3x4Oy9P3DKiOhgYjLOzy6uqCk1OdjQwiFm4UJXNBgA2G59/Lo/yozRdkK4nwtYUFyM9HWlpyMuTnnM8v5ejweHUC4U3583rY2bW/INMJlaswHOzVhqaV6Bri1BKXR2ys5GWhrQ06YGHWCK5mZt7LDX117t3GQRR+OmnOpTqSBJMJlau/JcDRhqa9vOWe8zICjU1ODvD2RkkicuXcfMmxGImgzGoW7dB3bolFRVFZWYeTUl5jyrKTRBQU6MVSCMr3nLfUZlDEBgwAM8GBwby+QBCEhOb37NYoNRIQyMLaBE+h4oKhg4FtQEDAJjs5KTKZv+TnZ1XVQUALBYGDlSaeTSdDlqEL6J/f/ToIdWhFpfrY28vIclD1GDI49FzURoZQovwJYwdCz8/GBpS5xCBbm6Qzkhzc1Fbq1zraDoTtAhfjp0dlixBUBCAsXZ2+mpq8QUFSUVFkEiQkqJs42g6D7QI/wsrKxgaspnMqc7OAA5Sg6F0k4aG5rWhRdgO3NwgnZEmJEhIErm5KCtTtlk0nQRahO2AzwfgaWnZXVc3p7LyRk4OACQlKdkqms4CLcJ2oK0NCwuCIAJcXSHdnqFnpDQyghZh+3BzAzCLzwcQmpzcKBKhpAQCgbLNoukM0CJsH66uYDKdDA3djY3L6+vPPXoE0IMhjWygRdg+VFVhY4M2B4aJiaDd32leG1qE7YbaI+XzmQxGRFpaZUMDamqQlaVss2jeemgRthtHR3C5ppqag7t1axCJjqWmAvSMlEYG0CJsNywWHB3RZkaamvqfOaZoaP4dWoQdwc0NgJ+LiyqbfTkr60lVFRobkZ6ubLNo3m5oEXYEa2toaGhxuWPt7CQkeTg5GaBnpDSvCy3CjkAQcHFBKxc2AHj4EPX1yrWL5q2GFmEH4fMBjLO311NVjREIkqmgCmpIpKF5JWgRdhBTU+jrc5jMKc7OAA4lJYEkceYMDh4E5VNKQ9NBaBF2nFZBFQcSEkgAJImHD3HgAE6epI/vaToKLcKO09AAYHC3blY6Oo8rKm7m5jZfFwqRlITTp5VpG81bCC3CDlJRgehoAARBTGsdVEEhFCIhgXbspukQtAg7SHS0tJRFkLs7gMNJSU0tVwBAKERICM6dQ3w8BAK0/oiG5kXQyX87SGamtPaTs6Ghk6FhanHxvPBwPxcXd2NjS6rMaG0t7txpvp/BgL4+TExgZARDQ5iZQV39355fXY2EBGRloakJ+vpwcoKdHV30onNDp8HvIL/+itJS6mV1Y6Pbb78JJZL8lsIy2ioqrkZGLoaGzoaGHqamvUxM1FrlL21GWxs8Hng8GBuDx4OeXrPGSBLXr+PaNZAkRKLmm7lcqKtj+nQYGCikezRKgBZhB9m3j4qcEEskE//++1R6ejcdnfH29g9KSuILC4ufTYXIYjDs9fXdjY3deTx3Y2M+j2eqqdn2gUwm9PRgYoKqKuTlPZVfa7hcLFhAV0TsrNAi7CAnTyI2FsAHZ85su3vXQE3t9rx5Ni3yKK+vTy4ujs7PjxYIUoqLk4qKGp8VlY6KiouRkYeJiYuRkbOhoYeJierzQ+XzEASMjLBokRz6Q6N8aBF2hMePsX8/xOItt24tj4xUYbEuzZ7d38LiZbcLxeL00lJKkMlFRXefPCl60VApFWRvU1OT54dKCg4HM2fi5W3RvL3QImw3FRX44w/U1Z19+HD8oUMSiWT/5MlUrRgAKy9cyKqocDcxce/fn29raykSoaDg+SinnMrKhMLC+IKC+MLC+IKCR2Vlkmd//yaamq5GRlWNjQs8POb27Pn0AwYDgwZh6FD59pFGGdAibB/19di9G6WlyUVFA3bvrmps/Gb48K8GD5Z+7vrbb8lFRdK32trarq6uLra2zubmHjxeL01NtaoqlJe3eWqTWPywtDRaIIjOz08pLo4rKCipq6M+IoCfxoz5sG/fp3fz+Zg0SY597KrExcXFxsby+XwPDw+lGECLsB1IJDhwAFlZgurqvrt25VZWBri6HpwyhSAImJpCRQWqqgkkGVddHZ+cnJCQEBcXV1JS0voBLBbL3t7e3dXV3dra3diYr6trKhJBIGizDUOSZFZFRVRGxurLl4tqa3uamMQsXPj04/79MXKkYnrcRZBIJFu2bPn0009JkiQI4sMPP1y7dq2Ojo6CzaBF2A5OnUJ0dL1QOHTPnrtPnnhaWkYFBXFZLPTrh1GjXvgT5eXlycnJ0dHR0dHRKSkpSUlJjS0FgCl0dHRcXFw8nJ1dzMyc9fQ8ystVW/1HxBUU9Pr9dzUOp2DFCg2qAhSXi4kTqdB+Gplw//79RYsWRUdHA+BwOE1NTQD09fW//PLLJUuWcLlchVlCi/C/uH4dFy9KSHJqaOjx1NTuurp35s0zVFeHrS1mzGjnMXpDQ0NycnJ8fHx8fHxCQkJ8fHz5s1NTNovlbGjINzL6afRoXVVVAAN3776Zm3twypTpbm4AoKaG5cvbVC+leTUqKyu//vrrbdu2icViMzOzTZs2BQQE3Llz54svvrh06RIACwuLr7766r333mMq5BdOi/BfSU1FWBhI8tPz5zfdvKmnqnrzvfccDAxgZIS5c/EaX5b5+fkpKSnS0TItLU0sFquy2VWff85iMAD8du/e+6dPj7O3PzVjBgDMmAE7O1l1qysTERGxZMmSvLw8Fou1ZMmS7777TkNDQ/ppVFTUZ599FhsbC8DZ2Tk4ONjPz0/eJtEifDkCAf76C0Lhn7Gx74WHs5nMs4GBI6ytoaGB+fOhpSXDpmpra5NiY3P//nuqmRmamgCU1debbNokIcm85ct5GhoICICDgwxb7IJkZGS8//77kZGRADw9Pbdv3+7q6gqgvr5eJBJpthwOSSSSo0ePrlq1KjMzE8CAAQM2bNjg6ekpP8NoB+6XUF2NQ4cgFP6Tnb341CkAv4wZM8LaGiwWAgJkq0AA6urqfT09p/7yCyZNQrduAPRUVUfa2IgkkiNULUQ6k81rIBQKN2zY4OrqGhkZqauru3Xr1n/++YdS4KVLl3r27Llq1SrpzQwGw8/PLzU1dceOHUZGRjdv3hw8eLC/v//Dhw/lZR9J8zyNjeT27WRwcOoHH1ArtM8HDSKDg8m1a8nUVEUYcOoUGRx8aOpUAP0tLMjgYPLbb8mGBkU03em4fPmyk5MTAIIgZs2aVVRURF3Py8uTTjV79uzZ8KJfb3V19fr166n5KpvNXrBggUAgkLmFtAifQyIhDx4kg4NLPvvMVk8PwGQnJ/GaNWRwMHnjhoJsePyYDA6u+/JLLS4XQPqHH5LBwWRsrIJa7ywIBIJZs2ZRMrO3t4+KiqKui8XiHTt2aGlpAVBTU1uzZk1jY+O/PCcvL2/BggUsFguAurr6ypUrKysrZWgnLcLnOHOGDA5uXL16qJUVAA9T05ovviCDg8nwcMXZIJGQW7eSwcGz3N0BrBs2jAwOJvftU5wBbzlisXjv3r16enrPyyw6OrpPnz6UMn18fLKzs9v5zNTUVD8/P4IgABgYGKxfv/6Fg+crQIvwWaKjyeBgyZo1M/l8AGZaWnnLl5PBweRff5EikUItiYoig4PPzZwJwE5fv3kyXFWlUBveTmJjY/u2eBr5+PhkZWVR18vLy5cuXUqdOpibmx85cuQVHn779u0hQ4ZQD+/WrduOHTvEYvFrGtzlRSgUknFx5OHD5M6d5I4d5Nq1ZHDwmqFDAWhyuXGLFpHBweSvv5L19Yo2rLiYDA4Wff21sYYGgPsLFpDBweTNm4o2462ioqJCKjMzM7O9e/dKPwoNDeXxeNTSbunSpdXV1a/T0IULF/gtbsO9e/e+ePHi6zyta++O5uRg61acOYPUVOTnQyAASYYmJ6+7coXJYIRMnuxubAxVVUyfDhUVRdtmYABjYyaDMY0uD9w+IiIi3Nzcfv75Z4Igli5dmpqaGhQUBODRo0ejRo3y9/cvLCwcNGhQbGzsTz/91Pps8BXw8vKKjY0NDQ21srK6f//+iBEjvL29qdPFV6ALizA3FwcOoLaWOpejuJGTM/v4cRLYOnr0eAcHMJnw91daNG2r3Ip/JyWJJRIIBCguVo4xbzAZGRljxozx9fXNzc0dOHBgTEzMTz/9pKmp2dDQEBwc7Orqev78eT09vR07dvzzzz8uLi4yaZQ6yUhOTl6/fr2Ojk5UVJSHh4e/v38qVa6rQ4+SiUFvH2IxQkPbhBpllZdPPny4QST6sG/fD6i1u68vrKyUYiAAuLmBIN4xM3MwMBBUV1+iaiEmJSnNnjcP6QHguXPnqAPAq1evurm5Abh8+XLPnj3Xrl3b1NQ0a9astLS0BQsWELLO1qOmprZy5cpHjx4tW7aMw+GEhYW5uLhMnTq1Qw/pqiJMTW09AAIoqavzPXSoqLZ2tK3tZsot29gYLfN+5aCpSR3cz2hdjC0+ns4vTLF582ZLS8tVq1Y1NjZSMvvoo48YDIZAIAgKCho+fPiDBw/4fP7169f37dtnIM8kPfr6+ps3b3748OGIESNIkjx69Oj169fb/+NdVYRpaa1FWC8SOfzyS1JRkRuPF+rnR3lvoiV9kzLh8wEEurkRwLHU1DqhEJWVyMtTtlnK59atWytWrCgoKLCysrpw4cK+ffsMDQ0lEsnOnTsdHR33799PnUzcu3dvwIABijHJwsIiKipKW1sbQF5H/o+6qggrK1u/u5GTU1ZfTwC7fX01pW7ZDQ1KMKwNzs5gsWz09PqYm1c3NkakpQH09gwAXL16lSRJc3Pz5OTkESNGAIiJienfv//ChQurqqp8fHxSUlKCg4M5VCCYAqG84Sw6koikq4pQTa31O3U2GwBBEA4GBgDK6ut/vHnzq8uXlWNba7hcKnjimfLASUl0TmEbGxsA/fr1U1NTA3Dr1q133nnn7t27VlZWERERERER3bp1U4wleXl5enp6lPYAUIGIDR35Bu+qIrSxQas0Z/0tLHqbmkpI8mRaGoDapqbPLlz48dq1ymcHTOXA5wMIcHVlM5nnHj0qqatDfT0yMpRtlpKh/talodL9+vUbMWLE0qVLExMTfXx8FGkJm80uLy+X5lJQUVFpbVh76KoipCJlWzGvVy+01P200NYeZGXVIBSGh4crwbY22NlBVdVQXd3L2looFtNBFRRtBhyCIM6dO/f6B4Cvb0mbb4f20FVFqKKCceNaD4b+Li5cFutCZmZBTQ2AwMGDAYSEhCjNQilMJpyc0KY8cGoqqqqUa5dyef5vncFQzh9zm6GPFmFHcHfHyJFgs8FgANBVVR1tayuWSEKTkwFMHTKEy+VGRUU9efJE2YY2z0gnOjpqcDg3cnKyysshFmPrVvz1F/LzlW2ccniFWZ+caKM6ek3YQXr3xuLF6NULHA6eHWp0nzwZM3KkRCIJCwtTspEALC2hpqbO4UxwdCSp8sAASBI5OdizhyrV1tV4hQFHThAEwWazSZKkUkXRI2HH0dXFuHGYNQvAeAcHbRWVu0+epJWUQCwO9PTEGzIjLS2lzkuk5YGffiQUIjKSKo/RpXhzRIhnjaE3Zl4Vc3Po6amwWJOdnNAy1Pjo6eno6Ny/fz+NOp1TImfOUF4y3jY2PA2N1OLiuIKCp58KhTh5Umm2KYlXmPXJj9bCo0fC18DVFa0r0ZOkSn7+5PHjARw8eFCZhjU0xN25Q4mQxWD4OTsDCL5y5Zl76urQWpZdgDdnTYhnhUevCV8Dd3cAw7p3N9PSyigru5efD5IMfOcdACEhIaTy3DU3rlvX+/fft929S73taWwM4HR6etv7CgsVbJhyeWOno/RI+Bro6cHUlEEQ01xc0LI9M5TFMjc3z8jIuCOtvKtYjh079vmGDRKS1G9x8TmYlARA6/mUpy31g7sIXK6KhcVgff3eyjYEeHb0o0X4elDxe3w+gENJSSKJhFFUFODrCyVtz8TExAQFBUkkkvXe3gGurgB2xcRczMxkEsSalgwLzTAY0NVVvIVKhMtVz839JzPznLINAeiNGVni5gYGo5eJiYuRUXFtbVRmJoBAd3cAhw8fFj5X50yu5OfnT5gwoba2dk5g4GeengAiHz1afOoUAfw1ceLSfv2euZsku1rpQjYbTCZEojfCi5bemJEd6upUCO90KqNEQgKAHnV1rq6uxcXFUVFRCjOkpqZm7NixeXl5gz09f+/bFxJJSnFxwJEjIolk9ZAhVAq2p3A4GDasC5apoAIkng0LVQ70mlCm8PkAZvL5BHD8wYOapiZUVk4fMwYKnJFKJJLAwMD4+HgHB4cTQUGcsjIq4LiiocHPxSW4TZ1QNhu2tmjJ4deloNbFb8LWDL07KlOcnMBmd9PRGWBpWdvURAVVBDo6EgRx/PjxmpoaBZiwbNmykydP6uvrR6xYoZuf3yAS+R46lFFW9o6Z2Z6JEwmCAIMBFgtcLjgcDB2KqVPbWRyqk0GJ8E04KaQ3ZmQKhwN7ezzrwtatuHjggAF1dXUKCKr4448/fv75Zw6HE7Z2rd2TJyRJvhcefis310pHJ2L6dDU2G6am8PLC8OGYPBmffooBA7qmAoHmDHhv2khIb8zIAj4fwDRXVw6TeT4jo7CmBg0Ngd7ekP+MNDIycsmSJQRB7Pr222GlpQC+unTpYGKiFpd7cvp0noYGDA0xaxb690f//rC3B4slV3vecN6c6Si9MSNrbG2hpiYtihSWkgLA39KSw+FcuHChUG5n4ikpKQEBASKR6Ovly2eJRCDJvXFx31+7xmQwDk6Z4sbjQU1NORlQ31TeHBHSa0JZw2DA2RktB4bUjFQvP3+Ut7dIJAoNDZVHmyUlJb6+vhUVFX6TJq0xNUVT07XHjxeeOgXg5zFjxlGD3vTpXe0w8N+h14Sdmpb4PW0Vldt5eQ9LSyESBfbpA/nMSOvr68ePH5+RkfFO7957vLyI6urM8l4flUwAACAASURBVPIpoaGNItHy/v2XvPMOAPj6wtxc5k2/1byZIyG9JpQR5ubQ0VFhsSY4OKAlqGKCSKStonLnzp10mQZVkCT53nvv3b5928rKKmL+fLXi4rL6+jEHDhTX1o61s9vo7Q0Aw4c/n4+D5s3ZmKHXhHKAIODoiJYZ6f74eAAqTOYkR0cAoZ9/Dtl5z3z55ZeHDh3S0tI6uWoVTyAQisX+YWHppaU9TUwO+/kxGQy4u2PQIFk115nQ14eeHpSU1OIZXvOwvktvr70UksSjRwC8rK3NtLQelZXdz8/vbWq6tG/f8Q4O45yccPw4/P1fv529e/f+8MMPLBbryPr1bgUFAD44c+ZiZqaJpmZ4QIAGhwNLS4wf//oNdTIKC0EQOHy4+W1ZGSQSyDPF9n9Ab8zIgZQUVFWBJBkEQcXvUdszPU1MJjs5cQE8evT6yV2uXbu2cOFCAD8HB3uXlgL4/tq1ndHRqmz2iYAAC21t6Opi2rQu6I/2nyxaBCenp6VxtmxBcLAy7ZkzZ879+/c/+ugj0GtCmXHvHpqaqENwaka6KyamsbWnsFCIP//Ezp04fhx37iAnp6MujJmZmVOmTGlsbPxkyZLFLBbE4qMpKasvXWIQxMEpU/qYmUFVFYGBbZIU00jR0sLKlco2ogUej+fh4WFsbCy9UtWRXHj0dPRFFBVJX/Y2NeUwmTVNTbyNGxe98w6fx3Pn8RwMDFgABAIIBJBmfNHQgKkpTExgZARDQxgYvNiXRSIpu3p19LRpxcXFExwdN/J4aGiIzs+ffeKEhCQ3jRw50dERDAb8/KCvr4jOvp189BE2bsTVqxg8WNmmtKKgoGDMmDEAWB3xo6BF+CKejaP/fNCgdVeuVDY2bmgptcNmMu309DxMTV0MDZ0NDfuamxupq6OmBunpkMa8c7kwMmoWpIkJTEzAZqOmBnv3qpeV9TMx0WAyD0yezCDJJ1VVE/7+u7apaW7Pnp9Q1UvGjkX37grt8tuGpiZ++AGLF+NVK3PKGLFY/Ntvv61evbqyspIgiOXLl7f/ZwklJm54c9mxo03Kltu5uddycuqEwvjCwviCgqzy8ja/NQttbXcej8/j9TA25vN4tnp6zDbbdgQBbW3U1kIkgkRCAlWNjdoqKtWNjZ5//plQWDjEyur8rFkcJhODBmH4cLn38W1m0iT4+GDuXAweDB8f1NSgvBy//qo0e2JjYxcvXkylX/Dx8dmwYYOzs3P7f5weCV+EuztKS1ufQ/SzsOjXKmq2urExvbQ0ubg4Oj8/WiCILyjIrazMraw81TIMcphMWz09D1NTDxMTFyOjHsbGBmpqqKho/nmCIABtFRWxRBJ47FhCYaGjgcHxadM4VLLtYcMU2NW3GILAb79hyBBMmQIuFwIBzpzBu+8qdCersrLy66+/3rZtm1gsNjMz27p1a0crhIIeCV+MUIiffkJt7b/dQ5Ktl3z51dWUIFOKi5OLilKLi9v8Wk00NDxMTV2MjJwNDT1MTJwMDRkE8eGZM7/evauvpnZ73jxbXV0wGJgzp6vFyL8C1Ej43nsA8Mkn+PVXzJ+Ppib88QccHbFunYKiuyIiIpYsWZKXl8disZYsWfLtt99qamq+wnNoEb6EggL89ReEwrZlcZlMqKpi8mRUVaG4GMXFePLkebmW19fHFxYmFBbGFxTEFxYmFxU1iEStb9Dkck00NNJLS1VYrKigoIGWlgDAYsHbu2tG6LYHkQhffYWPP8bixU9FWF0NJydMnIghQ/D5583lqgYOxMaNkF910IyMjPfffz8yMhKAp6fn9u3bpaXRXgFahC+nvBwnTkAgAEFALAaTCYkEdnbw8Wl7clBZicJCFBaioACFhSgrayNdsUTyuLIyuagoWiCIzs9PKS7OLC8HoK+mtrh372+kK0CCwLBhtH/MC2lsxPTpOH4cAwbg2DGoqUE66lBVyQwMIBTir7+wZk3zit7LCz/+KOOS50KhcPPmzcHBwQ0NDbq6umvWrPnwww9fsxYNLcL/orwcubmorYWmJqys0J7KW2IxysqQnw+BAMXFKChAXV2bW4pra5dHRh5ISHivV69dvr7NV9lsjB2LHj1k3Ye3nro6TJ6MyEjo6ODsWbRJc9WG2lr8+iu+/x5VVWAwMGUKNm6kkge9LleuXFmyZElqaipBEDNnzvzxxx8NDQ1f/7G0CBVCdTUEApw4gfp66bWHpaX2v/yixeUWrFihShVpY7HwwQfQ1laanW8ktbXw9cWlSzAywvnzaJPm6mWUlGDTJmzdisZGqKnhww+xahV0dF7RhoKCgs8++2z//v0A7O3tf/vtN6pGt0ygPWYUgqYm7O0xenTrioh2+voepqZVjY1nHj4EAIKArS2twDZUVMDLC5cuwcQEly61V4EADAywfj0SE+Hnh/p6bNgAf//jW7Zs6WjSbolEsm/fPhcXl/3796upqa1ZsyYxMVGGCgQtQoXC57cp0/1MJXoA48Ypxa7/oKYGSUm4eRPx8SgrU2TLRUUYOhS3b8PKCteuwcWlw0+ws0NoKG7fhpdX04MHnyxfvtzR0fHAgQOS9iUsj42NHTBgwOzZs8vKynx8fJKTk4ODgzlUrkXZQU9HFYtEgvPnER0NiQQSiaC62mLLFiZBCFas0FNVxcyZsLFRtomtqK/HqVNITweD0bw1RZIwNsbEidDTk3fjAgG8vZGcDEdHXLggg5DmqKiozz77LDY2FoCzs3NwcLCfn9/Lbm5zALhly5Z/ufk1oUdCxcJgYPRoLFmCQYPAZJpoag7v3r1JLD6WmgoArQsPKp3qamzfjrQ0iERoaoJYjKYmCIXIy8OOHfKuEJydjUGDkJyMnj1x9apskgp4eXndv38/NDTU2to6JSXF399/4MCB11tcEVsTERHh6ur6888/EwSxdOnS1NRU+SkQtAiVg64uhg5tLn3RphL9m5BQGgBJ4tAh1Na+IMs8SaKpCSEh8jM1NTV18eLwjAz064dLlyCLDchmGAyGn59famrqjh07jIyMbt68OXjwYH9//4fUshzIyMgYPXq0r69vXl7ewIEDY2Jifvrpp1c7gu+AVXJ9Os2/wecDmOzkpMZm/5OdnV1RAaEQz9c8UwpZWSgt/bdKTw0NuHABz3ogyIS4uLghQ4ZcuuT/7rvXL1x49f3Mf4HD4SxYsCAjI2P9+vUaGhphYWEuLi7z58//6quvXF1dIyMjdXV1t27devXqVTeFZBVhBis3HLIro6ODmBiuWJxYVJRUVGSqqTnQ0hIi0RuRTubq1TYTzlqhkEUQhNQZjCSRn48bN5CcjOxsFBejqak5KXg7IUlUVqKyEiyWNIHq/fv3R44cWVJSMnLkyH37PlZXZ//7M14HDofj6ekZFBRUU1MTGxt7//7927dvC4XCOXPmnDx5cvjw4YSisirTGzNK5fx53LoVkZbme+gQn8eLX7wYDAaWL4e6upIN++OP1iJcEBGxNy5OKBa78ng9jI09TEw8TE17GBtrPC85FRUYGj6NqzQyeoE/dVMT/vmneXeKyYRQCD09jBhxtbDQx8enurra19c3NDSU+3wNRrmRkJDQq1cvkiTPnTvnTSXXUiBvYhTFzZs333///bS0tKFDh3p7e/P5/B49eui/ToRrbi6uXcPjx83f1hYWGDQIlLumcuHzcevWaFtbAzW1hMLCxMJCNx4PKSmg0hwqkVZ+WOczMnbFxFBf1omFhYmFhVTmKwZBWOvqUqFb7sbGfB7PSkcHDQ3IzUVu7tPn6Os/DXQ2M4NIhD//RF1d81SWClUpLj67fv2Ugwfrm5pmzJixd+/eDgXFvj4EQYjFYltbW8UrEG+gCKuqqsaMGUNlBzh79uzZs2ep67q6us7Ozh4eHh4eHi4uLm5ubu06riFJnD2LuLincUmNjXj0CI8fg8/HuHFKLuRgbAxDQ3Zx8VRn59/v3z+YmPgDj4eEBOWL0MQEeXkAHpSUBBw5QpLkODu77T4+jysrKd/X5OLiGIHgUVnZo7KyIykp1A9pcbluPB4V6OxhatrT2Fidw2l2c5fCYDy/1DyZluYfFtYoEi309f1t//7XdMVsJ6NHjyYIYufOnRYWFvHx8QDc2+8KIFPeLBGKxeLAwMCqqiodHZ0vv/xSRUUlKSkpISEhMTGxvLz8xo0bN27coO5UVVV1dXV1d3d3d3fn8/nu7u7aL/Q1iYpCfPwLMhQKhUhIAJuNUaPk3Kf/ws0Nly4F8vm/378fkpj43YgRjLw8lJUp4CDupZAkJZvSujrfQ4fK6+snOzmF+fszCMJCW9vT0pIK4xJJJGklJZQgqTAuQXX1jZycGzk51GOYDEY3bW1KkJQynQ0NiecUeDAxcfbx4yKJ5NOBAze88w5RX6+A2bhQKLx8+bJIJNLV1QVAi/ApH3300alTpwwMDG7dumVra9v6o/z8/Ojo6Ojo6JSUlOTk5NTU1Hv37t27d096g4mJiYuLi3S0dHJyYpSV4e7dl+7gCYWIjkbPnjAykmun/gM+H5cuDbSw6K6rm1Vefj0nZ3C3bkhKUmbulMhIZGc3icVTQ0Mflpb2MjHZN2kSo/WUgcEAwGIwXIyMXIyMpCdo5fX1UkFScZWZ5eWZ5eXSWGdtFRVXIyPpUOlhYrIvPn7J6dMSklzp6bneywsMBpKTFRDMlZqa2tTUZGdnp6GhAVqEUrZu3bpt2zYVFZWTJ09SCqyrq+NwONTywNTU1NTUdHxLEs6qqqqEhARKkNHR0XFxcQKBQCAQSOvpcjgcW2NjD11dKra9p7Gx/vOZy0Qi3LunZGcxbW1YWBC5udNdXb+/di0kIWFwt26Ij1eaCGNicOcOSZLzTp68kp1tqqkZPn26euuZP4sFTU3MnQuShECA/PzmCWdxsa6qqqelpWfLYrtRJEouLqaCKhMKC+MKCsrq61sPlSwmUyKRkCS5aeTI5uQ6lDOA/EXYRnUJCQmgRXj27NkVK1YQBLFr167+/ftTF3/77bcvvvjCzs6OWgc6Ozv36dOHx+MB0NLS8vT09PT0pO4Ui8Xp6ekJCQlxcXEJCQnx8fFPnjxJyclJycmR7iKoslgOBgbnZs40lM52SBJZWUrobRv4fOTmzuTzv792LSwl5ecxY7hlZRAIYGKiaEsyMnD6NIB1//yzPz5ek8s9ExhorqUFAFxuc5Bk794YOrTZA5ZyTKdobERhYbMg8/NRUMAFepmY9GrVi/zq6pSiouTiYiqu8kFJiSqb3dvU9JNW4be5hYUKyCzQWoQFBQWFhYU6OjqWStqreyNEmJycPH36dLFYvG7dusDAQOn1/Px8kUiUkpKS0rL0B2BhYcHn86ktU3d3d1tbWyaTyWQynZycnJycpk2bRt1WUVGR9PXX0Q8fSncRaoXCGIFg0F9/Pfjgg6dtvwkeKi4uOHfOydCwh7FxXEHB2UePJjo6IiFB0SIsLkZYGCSSsOTktVeuMBmMA5MnuxsbQ1UVfn5gs6GiAn39l25lcbmwtHy650ySqKhoFiQVV1lebqqpaaqp6dXiHxsrEPTeufNOXl5+dbWppmZhTc3YkJBCoTBj7lx5n0+0FiH1ms/nK+xgsA3KF6FAIBg7dmxlZeW0adO++uqr1h9t3rx57dq16enp1JwzOjo6Pj4+Nzc3Nzf39OnT1D0cDsfW1la6a+ru7k7FWero6Hj26OHZcrDRKBJtvXNn1YUL2RUV9UKhqjSUQc4eSe1CVRU2NkhPD+Tz4woKQhISJjo6IikJI0cqbvO2pgYhIWhsvPfkybsnTpDAllGjfB0cwGTC3/9VQmIJArq60NV9OlQ2NOD4cTx8KE070NPEZKKj47HU1K23b2/09jZSVycJ4klJyb59++bPny+zrr2I1vNP5S4IofTD+vr6+mHDht25c8fT0zMqKqo933/P79C06YKJiUnz9JXD8aisdNLVlW4q9P3jj7tPnhz28/OnomJYLAwZgpY5rTJJSsLRo/nV1ZZbtrAZDMGKFToqKpg1C9bWimhdJMLevcjLy66o6PvHH0W1tfM9PHZSy+9Jk2SZH6KyEtu2td6sjhUIPHbsUONwsj/+2EBT8++CgunbtllbW6elpcnvqFAgEJiamuro6JSVlREEERgYePDgwV27dr1HZa1ROMocCUmSnDNnzp07d7p373706NF2zkDa7NBUVFTEx8dT68D4+Pjk5GSBQHDq1KlTp05RN2hyuYenTh1jZwcgkM+/++RJSEJCswgZDHh4yKVvHcXREVyuKTCkW7dLWVnHU1Pn9OyJhARFiJAkER6OvLyqxsbxBw8W1daOsrX9jdqsGjJExhlatLUxaRKOH5fqsKeJyUhb28hHj7bdv7/G19fv44/XXLiQnp5++PDh1gsT2SId+qj5p9JHQmU6cK9aterw4cNaWloRERFGr3pOoKOjM2TIkA8//HDXrl337t2rrq7OyMg4efLkmjVrfHx8rC0sapqaLFqOEKe7urIYjLOPHpVSSV/69YOqqqy681qwWK2LsTWH+SYlIS3tBXEMsuXSJSQliSSSqaGhSUVFzoaGh6dOZVHliocMkX1zTk6YORM6OuBwKJfRL4YNA/Dz3bvVM2YwNTRWrlwJ4Lvvvmtn3O0r0Fp1jY3Q1+/v5OTh8gohwzJCaSL866+/Nm7cyGazjx07JsP+M5lMa2vr8ePHBwcHR0REZOTkFN+/72hpSTkWG6qre1lbC8XiZicPxcaJ/wdubiDJKU5OBmpqZpqaYokEYjGOHsX//ifHVO/x8bh+HcDSs2cvZGQYa2icCQzUVlGBqSkmTpTXitTSEkuXYtYsjBgBL6/BS5YMGjCgrKbm9z17AMyaNatbt26pqaknT56US+tAUdGwoUNX9+kzHkByMq5e/QO4r6q8r2PliPDq1auLFi0C8PPPP8s2Xcfz6PfqxVqxAuPHU/VVnhlq0tLeiN1Riu7dwWYzCGL/5Mm/jB1LZdEnm5qiUlObTp/G+fOybzEnBxERADbdvLn93j0VFut4QEA3HR3o6GDGjNZpOGQPQcDcHP36YeBA9OjxxerVAH788cf6+no2m/3JJ58AWLdunZw2LM6d63PlyjpHRy8A8fEAOpC6Rh4oQYRpaWkTJ05sampauXIlJUW5w2TC1ZWqtjnJ0VGDw7n++HFWeTmEQjx4oAgD2kN0NCSSjPLyMQcOrLxwgbomIUnvffsqqqpw/z5kWqYb5eU4fBhi8en09FVRUQTw54QJ/czNweVi+nQFh3GMHj26d+/ehYWFf/31F4D58+ebmJjExsZKXS9kSGMj0tPBZIKqFtEVRVhaWjp+/Pjy8vLJkyd///33Cm3b0hI6Ouocjq+DAwn8nZQEvDEZJSQSXLxIeTYbqqufSk+/nZf3zA1CIU6dQk2NbJqrr0dICOrqYgWCaUeOiCWS70aMmO7mBgYD/v5K8eNbtWoVgPXr1zc1NamoqFAFN9ev3yTzhpKSIBLBwaF5N6DLibCpqcnPz+/hw4e9evXat2+fYpzln0IQVL6u5kr0lPwyM2X2l/06tJKcCov17fDhCyIihK23ZEgSNTX48Uds2IA//8S5c4iORk5Ox2Lba2ubz83DwlBaml9dTZVke7dHj8+ptN9jxijoUOQ5Jk2a5OzsbGQ088iRGgCLFy8eNerwgwdnXpQC5rWg/tulqqPWJcoVoeKOKEiSnDdv3uXLl01NTcPDw9WVErfq7o4bN0ba2PA0NFKLi+MKCnoYGyM5GX37KsGY1pSXt86cH+TuviM6+uc7dz5uyTV9PTfXTFOzu65u24A9JhOGhuDxwOPB2Bg83ouL+yYm4vJlVFeDxUJTEySSOqFw4t9/51ZWDurW7XcfHwAYMAC9e8u5ny+FwWB89dW9GTPU1q1DQAC0tLT69PGPjMQPP6DFL0M2UEMfdfKSm4vSUujrw9RUlk10FMWJ8Jtvvtm/f7+GhsaZM2fMZZI96xUwNISREauoyM/Z+de7d0MSEnoYGyMxUfkiZDBab0USBPHbuHHD9uzxb9k3nvj336V1dZpcrr2+PlXX6WnAXkHBM9UU28S2GxrixAmkpzcXtxGJAEhIcsbRo/eePLHW1T3q789lsWBnBy8vxfa5Lf7+al9/jbQ0HD0KPz98/DG2bMGZM4iOluVpbuv5JzUqKr3sgIJEGBYWFhwczGAwQkJClHgqCgB8PqKiAvn8X+/ePZiYuN7Li/nkSfP3oRLh8SAStR4MexgbB7m7f3npEoDapqbepqbxBQUFNTXR+fnR+fmUVzqTwbDV05NWJnXn8Sy0tV8Q206SzU9u0fmK8+fDHzzQU1U9S7mzm5jAz0/J8c0Ak4lPPsHixfjuO0ydCj09LFiAzZuxfj3CwmTWSuv555uwIIRiRHjv3r13332XJMmtW7f6SoufKAs3N1y82M/c3E5f/2Fp6dXHj4d1747ERAwdqkyr8vMhFreRwbphw5y3bQOgzuGcmzkTrQL2pKG0aSUlaSUlYcnJ1I+0CdjrZWKi9txJw+6YmC23brEZjDB/f3t9fXC5CAiQ74FEu5kzB99+i/h4nD2LsWPx6afYvh3HjiE5+VXSbz8PNf80MGief7aemioRuYswOzt7/PjxdXV18+bNW7p0qbyb+2+0tGBpicePA1xdv/nnn5DExGHduyMhAUOGKG0oyM5Gi5Nda7RVVDZ6e888dgwACAIk2SZgr01s+/38/IKammcC9hgMy5bYdg8TE0cDg/C0tFUXLgDwsbcf3r07AKiqggpWegPgcrFsGVaswDffYOxYGBtj9mz8/jv+9z/s2SOD57cZ+t6QkVC+Dtx5eXleXl5paWmjRo06deqUgrP3vJSYGEREtC2KNG8ezMyUYEx5OXbtQl1d+IMHZx4+/HXsWHab9GQEARYLkyeje3eUlaGoqDmUtqDg+bQd+dXVVFlSKo42vbRU9BLnL2dDw+T33wcABgOrV8ula69EbS26d0dxMS5fxtChyMqCvT0IAmlpoL40XoeLF7F+PQYNwtdfo74empogCNTUQIGJ3V6AfPOOOjs7Z2Vl2djYREVFKdEtqC26urh9W19F5XR6elZFRU8TE2dDQ7DZeDahhiKor8fevaiqihEIxh86dDsvz97AgM/jAQCb3ZyN09oaAQGwtGwOaTc2hq0tevbEoEHw8ICVFfT1m8/W6+o0uVw7fX1PS8upzs7v9+nzuafnNFfXvubmjysrC2pqWAwGSZJ8Hg8EkV1RMcnR0VhDAySpzFnAc3A4aGjA5cvIz8esWdDVxaNHiI2FUCiDFAjW1ggKanaJbWiAtjZ69MDo0a9v9Wshx5GwsbFRVVWVJMmIiAgfahMcEIlEb8R4ePgwHjzYevv2snPnJjk5HZs2DWpq+OQTKPLoUiLBgQPIysqvru63a1duZeXsHj32TJwIAKNGwcoKBAE9vQ6s1p6LbZcOlTdycjz//NNMS+ve/PkmmpofnDmz7e7dTwcO3OjtDQ0NfPKJfHr4ilRWols3VFbi5k30748HD+DiAjYbmZkyOEt49Ai7duHDD5vnPTU1+PZb/PCDMr+F5Pg3x+VyqQxoOTk5AEQi0cyZM83MzGqfq/CuBNzcAMxwc2MxGKfT00vr6lBXh8xMhdpw+jSysupbndftkJ7X9evXfOjXof0SKrbdwwOjR2PuXKxahWnTqNy7AywsrHV1n1RVpZeWolUBDHGLA8MbhbY2KHfGjRsBwNERCxZg3TrZLF2zs7FhAz7+uPltbS02bIByM2DL94v/u+++A3DmzBkALBYrOzu7qKjoxIkTcm20XdjbQ0XFSF39maJI0jqBCuDaNcTEyPe8jsGAoyMsLcFgEAQxvVUtxP4WFnb6+vnV1ddyc9+ImObnWLYMqqoIDwflXLh9Oz77rF2lytuDqyvi43HmjGye9vrIV4QBAQEcDicyMrKwsBAAFaYZEhIi10bbBYsFJye0CapQWFGklBRcvgzg0/PnT7Q+rzM2lv153dSp0NICizWTzwdwJCWlUSQCSU5zcQEQUlUlsz9tmcLjYc0a7NoFBwfZP5zNxqZN+OADUFGlSke+ItTT0xs5cqRIJDpy5AiAadOmcTicCxcuUJpUMm5uAKY4Oamz2VelRZHOn0d1tXzbzc/HiRMgyd0xMZtv3WIzmc3ndZqamD5d9ud1ampYuBCOjo7Gxj1NTcvr689kZYHLDRwyBEDouXP19fUyblFGTJ2Kc+eezk6EQvj7o0NLGaEQGRm4cAE7dmDlSvj54dNPmz/y9YWTE775RsY2vxpy34doPfrp6emNGjVKJBKFydAD4pWxsoKWljqH4+PgQAKHqXlPTAx+/hlHjqChQS6NVlbi4EEIhVeys5ecPg3g17Fjh3fvDjab8piUS6MqKpgyBR99FDh9OoAQgQDvvuu4bp2Hh0dVVZW00MCbRlkZjh3DggXNqQXEYoSFvXSmUl6O6GiEhWHDBixcCG9v2NhATQ22thg5EosWYeNGHDmClhAxAPj5Z/z22xtRik7uiZ7q6+uNjY2rqqrS09Pt7OwOHz4cEBDQr1+/W7duybXddnH4MB48oIoiPT03A8BkQlMTCxbIOPlFUxP+/BOFhanFxQN2765oaPhy8OBvhw8HQWDaNLlMvJ5FIBBYWFiw2WyBQKCjo7Nly5bly5dPnjz56NGj8m76Fbh3DwEB6NYNEydi6VI0NEBVFSUlqKxEZiYyMpCZ+fRfRcULnsBgwNwc1tZP/9nbo7wcn32GmBgAWLcOkZG4eRNisUL3xdugiGxrQUFB+/fvX7du3erVqxsaGoyNjSsrK9PS0uylyfCUQlUVfvkFIpFQLDb98ceSurqExYvdqDM6AEwmrKwwc6bMmiNJ/P030tNL6ur679r1qKxsqrPzYT8/BkFg1Ci0REvIGy8vr4sXL+7evXvu3LmUJplMpkAg0FNi6YuXQInw+HEMHYrEROjrQ1UVAgHMzF5QvJTLhZnZM3qztoaT0wtCCWdJuAAADyZJREFUSqKinoqwsRHu7s15fJQoQkW0TM1I9+/fD0BFRWXixIkA/v77bwU0/W9cvUr9Z7KZTD9ql6L17qhYjOxsJCf/W7XaDnH2LNLTG0SiCYcOPSor621qupcq8NCzp8IUiGdXByYmJsOHD9fncB6+qTNSAHw+Zs3CsmXNb7lc9O6NIUMwZw6++QYHD+L2bRQVoaGh7fLPw+PFQV16ek9jZrhcbNsGLy8luyooYiQUi8Xm5uYFBQX379/38PC4cOHCyJEjbW1tpYXClcKW8eODnJ2pAhXUWbappmbOsmXMNl+JVIU9Q8Pm+CBT0w5sJzY1oawMJImMDFy8SJLkrOPHQxISuuno3Jk3j6ehARsbzJihyC/hqqoqY2PjxsbGx48fm5ubFxw+bDxnDvr2pXZr3yiokTAjA5WVcHLC7t0YOxZlZdDVVbZlskYRzitMJnPatGk//fRTSEiIh4fHiBEjzMzMHj16dO/evXeUVIjvfxs3fnbq1N5792IWLWIQRF9zcx0VlUaRSGf9egcDA2nAXnMx2jYV9jQ0miNoqfN0ff0XqKioCOfOIScHLBYkEspzZc2VKyEJCZpc7snp03kaGjAwwNSpCp4GaWlpbZozZ0hSksHRo/joI+OxY0EQuHoVubmwUEANiFdBWxv/+x9WrFC2HXJDQRm4792716dPHxMTk9zcXCaTuWzZsq1bt3700Udbt25VQOttOH369IQJEyQSycEpUwJcXQEsj4zccuuWJodT/ezuG4MgbPT03Hk8d2Njdx6Pz+N109Fp+7jni9FmZyM8vE184OGkpOlHjjAYjBMBAT729lBTw3vvKacIYXg4Jk5Ejx7NmRSnTUNoKDZufLp//2YgHQkpRozApUudcyRUXBp8R0fHtLS08+fPe3t7379//5133jEyMnry5ImCXUljYmIGDx5cW1u73sdnZe/eAHbHxMw7eZLNZJ6bObOXiUlSUdHTYrT5+fXPJnFpU4z2hQF7VNhR6wvXc3K89u1rFIl+HTv2/T59wGJh9mwoK71AUxNMTVFaisREuLri5ElMmAB3d8TFKceel5CdjT/+wHffNb998ABbtmDLlhev9N5qFCfCdevWrVmzZvbs2Xv27AHg4uKSkpISGRk5cuRIxRgAID8/v2/fvnl5eXMCA/90cUFT0/mMjHEhISKJZOf48fOfS6LwwmK0rW9oXYyWKoTYXUenTXGfrPLyfrt2FdXWftyv3xbKY3/yZMpVQGksXIidO/HFF/juOwiFMDFBaSkSEpRsVVdFcSLMyMigCqMWFBSoqal98803X3/9dVBQ0N69exVjQE1NzaBBg+Li4gZ7el7w9+eUlUnP674aPPib4cOfuZsgQBDPb422KUabVFTU+OxQqaOi4mJkRAnSVk/PSF19amhoWknJGDu7iOnTmVRw4KJFMDCQd3//jatXMWQILC2RnQ2CwOLF+P13rFqFH35QplVdFYVWZerXr9+dO3cOHz7s7+9PaVJNTa2wsFABmdckEsnkyZPDw8NtbGxuf/aZgUDwgvM6KWw2XFzg64uamjbFaNs8lipGS8XRUiVpy17kBeZgYHBv/nxNKnSUw8GECc2pZ5UFScLaGtnZuHYNnp64fh2DBsHSEllZyjwv66oodD0WGBh4586dkJAQf39/Gxsbym8mIiIiICBA3k1/8skn4eHh+vr6Z1etMnjypEEk8m1zXsdggM2GSARdXYwYQZVngabmqxSjLS5OLiqKFgjOP3pUWFtrqK6+d+JEzdbB2/Ku8fKfEAQCArB+PUJC4OmJgQPRvTuysnDjBqgEpDQKRKEjYXFxsZmZGYD8/HwDA4Nt27Z98MEHPj4+ERERcm13165d8+fPZ7PZkVu2DCspecF5nbU1xo1DUxO0tTvgqvaiYrRtbqlqbNRqkzuBw8Hs2UrOdAkgJQUuLtDTg0AADgdffIEffsDChfj9dyUb1vVQdJHQsWPHnj17dvv27YsWLaI0SZLkkydPXrk02n8SGRnp4+MjFov3btw4q64OJLn60qVvr17V5HKvz53L5/FgYID33oOKigwaa2jAr7/+h6u/mhpWrHgj0km4uyMhAeHh8PVFaiqcnaGrC4FAyRlXuh6KXgC0dpsyNDT09vaWBjrJg9TU1ICAAJFI9NXy5bNEIpDk4aSk765eZTIYB6dM4VP5qqdPl40CAaiowMeHKsP2Yjgc5XtJSaGqcFLhnU5O6NED5eU4d065RnVBFC3CiRMnamho3LhxIysrC3IO8y0pKRk/fnxFRYXfpElrTU3R2Hg9J2f2iRMk8NPo0T729mCxMH26jE/MHR3h4fFiHbLZcHZGz56ybO51CAwEk4mTJ1FZ2fzW1VXJmR66JIoWobq6+oQJE0iSPHToEFo0eevWrUxZ53dpaGjw9fXNyMjo7eGxx8uLqK7OKi+ffPhwo0j0cb9+7/fpAwC+vnI5MR85EmPHQlUVXC5YLLBY4HLB5WLkSEyYIPvmXhkzMwwahIaG5qyny5YhMRFUpikaBaLoNSGAs2fPjh071snJKSUlBcCsWbMOHDjw7bfffvnll7JqgiTJmTNnHjx40MrK6vbnn/MEgrL6+gG7dz89r2MwMGwYBg+WVYsvQCJBTg6oHAKGhujWDW0Sir4JXLsGkQhDhuDJExw7BoEAFhaYOhXSkC4a+aOEQyFvb28ej5eamhoXFwdg5syZBEGkybQC5tdff33w4EFNTc2Tn3/OEwiEYrF/2P/bu9uYpq4wDuDP7aXVOoRudYTyIoiKQBtw4izC3BuECWEq4jRx0yCoc8aYkPHFmRmiyYYuW2KWLTJf+GAMmGXq5AO+db6MIGqaANFuZbIObAsGgVFBbEt794GFAS7b6u7twfb/+9ab5t5zm/xzT8895znfmh880EZE1BQV8TIZabWSj8XLZBQfT3o96fWUkDAVE0hEy5bRG2+QwUBaLZlMpNHQzZu0YAE1NrJuWTARWNixYwcRlZeXC4Lgdrvb29tFPHlNTQ3HcTzP1x08KFRUCBUV7y9eTESamTM7y8qEigrh2DFhZETEKz7bXC4hOlo4fPivI59+KiQlCV4vuzYFFwbdUSJqampaunRpVFRUZ2cnL+ojoqGhIScnx+l0frVv33Yi8ngqGxp2XbqklMuvFBcviY4mlYq2bAnAWcBPzWSiRYtocJDGZtIPDJBKRVYrm30Bgg+bOUoZGRmJiYl2u/2cqAPilvb21atWOZ3Osk2btoeEkMdz6qefdhsMMo47sXr1kuhomjaN1q9HAifo6CCNhsavZQkPJ5WKOjrYtSm4MKtIr9Vq79+/X1BQoNFo0tPTtVptSkpKenp6cnLy02yj7XQKP/xQtHlzT2/v28nJn82eTU6n0W7fePq0VxA+y80tTE4mmYzWraMXX5Tgbp5lavXkiT4jIzQ4iB/Kb9h0R69du5abm+tyuUJCQtwTtxYKDw9PS0tLTU1NTU1duHChTqf7951kHA46epQePTJ2du65fPnkO++EKhQ2h0N/5IjN4Sh56aWjoy8GCgrE3PE1YAwMUEQEXb9Oixb9eeTSJVqzhnp6psimhQGPQQgtFoter+/p6SkrKztw4IDZbDaZTHfu3DEajUajsaura9L3Rx+VY0/LlJSUCQv2vF76+mvq7x+/7Oih07msurqlu/u1+PgLGzYoeJ5eeYWys/1zg8+eDz+kixfp2DHS6chopOJiKimhXbtYNytY+DuEfX19mZmZZrM5Ly+vrq7uyVGZ/v7+sUCOhvPxxDq84eHhOp1urPuazvPKK1fGF4X1eL2FJ0/Wmc1Js2Y1lpY+r1RSQgK9995UmSw2BXm99PnndPw4Wa00Zw6VltIHH+Dn8hu/htDtdufl5RkMBq1W29jYGPYfCk673e62traxR+WtW7cmldCftBltdFhY+YULly0W9YwZTZs3zxudkpaRQW+9JdFNAfxPfg3htm3bqqqqNBrNjRs3Yp+2tpfVam1tbW1tbW1ubm5pafmlrc3zxPp3juOuFhcvi4v78/Ps2bRp0/9pOYB0/Dc6WllZWVVVpVQqz5w589QJJKKYmJiYmJj8/PzRj+59+9q6u0eLTdyy2S7/9tt0nt+6ePFfCSQSrYAvgAT8FMJTp07t3r1bJpOdOHFiyejkaZHI1Wqt16sdtxxxeGREOf6tF8dRZKSIVwQQlz9e1huNxo0bN3q93v379xcWFop89rS0SSPpykk1FOVy0ulEviiAeCQPod1uX7ly5dDQUElJSbkUVZRffvmfXmfxPEVG0viuKcAUI20IH3oeln1RZrPZsrOzD0lUvEShoHffJYXib4bUeZ5CQ2ntWkmuCyASCUdHPYJnxa8r6n+vX1O/5psd36ieLCAvor4++v576uoimYw8HuJ58ngoJYXy81ExBaY4CUO4897OL3u+VIeory+4Pn/afImuMkF/P1mt5HLRjBkUF4eJ2vBMkCqEhx8c3tq5VcEpzs87//rM16W4BEBgkOQ/4XnH+e33tnPEHYk7ggQC/DPxQ2h6bFpnWTcijOzR7NnwwgbRzw8QYETujna7uzPMGR2ujrXPr62dU8sRJgED/AsxQzjsHX7zlzebhpoyn8s0zDdMl4lUURcgoInQHa131NvcNoGE0o7SpqGmeEX86bmnkUCA/8jnEP44+OOq9lVJpqRMc+ahB4eIqKKrovlR80f2j2r6a8L4sLq5dREhUm0sARB4fAvh1cGry+8uzwrNOjv37CdRn9T21VpcFiJqGW6p7K6Uc/LvEr7TKTFRE8AHvv0nzLublzg98WDMwfEH9Wb9x5Ef33x0M1Yeu2XWFrFbCBDgfFvKdHv49s6InU8e54jbq9krUpMAgotv3dFeT6+Kl3IKKEDw8S2EsfLYe657EjUFIDj5FsKs0Kzq3mqBsIUdgGh8+0+4N2pvljlr+d3lRaoip+A85zhXG18rUcsAgoTPM2YGPAPH+47//PhndYg667msnLCc6t7qV0Nf9dNiJYCAw6YMPgCMYbMrEwCMQQgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARhDCAEYQwgBGEMIARj7A9zmpVCyz/RQAAACTXpUWHRyZGtpdFBLTCByZGtpdCAyMDI0LjA5LjYAAHice79v7T0GIBAAYiYGCFAAYhUgbmAUBLMZ2Rw0gBQzC5tDBohmZsTGgCphSACZxMTOAOYzs0FoFg4IzQSTh6lnh9DMMJooq6AMYvQQLYNwiAWIZmTG1MPNwMjAyJTBxMScwMySwcTCmsDKxsDGzsDOocDBqcHEwcXAxc3AzZPBxMObwMuXwcTHn8AvkMEkIJggKJTBJCScwC6iICKawSQqliAmnsEkLpEgIQmkpBSkpBOkZTKYZGQTZOUSWOUzmOQZE4S5EyRFEuSkMpiE+RKcWIEuYGOUZ2VhZmLl4Rbm42XjFxAUEuZjExUTl5AUYZWWkpOVEe9iBEYWAywW/VyPHrDbPuUAiNOgvewAq38CmB3nse0A50NWMHuC3vQDrmzF+0Hsk+/9D2gpzAGz+bbpHxCs0wCryZu4aP/UM5Zg9t0VM/ZZRT0EqynbMM1+4W9GsPhb5ev2czJjwOzr3ZwOSwqSwWr0fqY7RIVOAbOP7elwaNqtAFaTH7DDwZRZBMze+P2AQ0V4GFiN0o2XDmsvBOwFsVnrXjj8St1pD2JXOO9zWBTG5QBisyVPdeDl2AAWV947zUHP/R9YfbS1736unxv3gdgBPnp2UY3eYDUbl6/aF+THC9Y7q+X5/mtz5MDsF18ND+z9tQqsRneP4IFVwvPA5nD8ET5wiasSrOaqaMGB9/xdYDbfqaID/Ny7wGyhGIkDb9RPgdn7Onbvl1ZaAmavepl7oHNuIdhfYgDEDqUa+O31pAAAAvh6VFh0TU9MIHJka2l0IDIwMjQuMDkuNgAAeJx9VluO2zAM/M8pdIEVxIdE6bObLIqi2ARot71DgX72/uiMk5W9qFA7IhRnRA/JIZFT4vXt8vXXnzQvvZxOKZX/fMYY6aeVUk6viZv0/PL5yzWd3z49vz85335c374n02QNZ3B/xH56u72+P5F0/p2eWpbmISU9ecbG2kgll+3aD2s6p6eaZWgn0nIt3tUWSLsj22hmnp40lyG9lQXSifQc6k5kycOHiS+QlUjL6qPw7ZJVRiDEf5GNSM3h1Xtw10zbWPkMIuEpSmlG5CgmsvLZ05XsdHQhUnK0UltbIAd8SpYIRcAM3croqyQhihuQrZfoztCQguErl4IiJc3iQ+iz5N67W6yQrJHlpl7pEzxq77WukIaIHKFb8a1EVcR9iXQga46K2DuRJkjnkidr1BixQnjkaaGxSqewRpGtBBRCZKnI0kogEhtSWzVkUZCk7rqk2QGs0E+FfJmtJjiyArJCkHnrht8lW1Rdpl3LliK0BZJIkqIuddkZLBDjLdIouZLNIZBV1ZUVgqsoKvw9IHhfAu3u03BBAJq1xCiryNXvMu6lB5pIs0e3ZV9qfbRGh96dsVuNWAlJH02kESKb5gp2fZmmuEMhC60d6utDtC+J9nsPRxVD5zqO+FpzOthvQA6rXVHWLtbrSh/GIvHtCAmVbfAZFsuhJPc0eYPUBT5FB5t5gdQHT7hiObGjRlavf7lePozT+4B9vl0v+4DlrfsQRYWS7ZPSufZxyLvuMw9fUtsHm2DFPr0Eq+8jSrDGPocUS47jRvhADlNFNjO5CcnByKQn5Acjk6GQIIxMkkKWMDJ5orudRiZVdLHTyGSLdnUamYRRPafRYwMyJJ2U0WdOo3s6t3wquuXQN06jk7KSMoxOykrKMDopK3NLzKSspAyjk7KSMoxOykrKMHaUo6dNbAfZOapmkzKVT7M/2BiXQyFsY9wOkRsZw9XOz9rj1IyKWjwqj9/f/xZgf/oLGcSPPCvGPC0AAAGHelRYdFNNSUxFUyByZGtpdCAyMDI0LjA5LjYAAHicJVI7jtxQDLtKyhng+UH/D4ytptlqc4AgldtgTrCHD+V9lUxQFCn598fr8br4/b7kwnuzPL8GuK7H698TCD/n43ocIPx5f/4FETD/+n7wjqKsdeg20/Z18uZMiXXIJqWudcpmawZCu6pMc526Q8zRBrZXoc22pJJNmzObrdN3epcMoixoihEUu3U0JWWduZUydCByDCMdTMK1FsNRmYxQm6ct+Ah2m1kRpQaGpss9PJm8R4bFGNWJUrp4tHlnkMMAKkmiO1uTMgOSnebWA4VKTKdCLbVnJwl9DDx8c0vxQE6GUOcRcGMJCG4sZylgRYfqvbrmCkBwJljsOGtrZbv1xZp4jAl36m22iKNyeGqwCxBZkoR10U702g9P8WBctlA235mKCiKyLUvljoR944K6q1n65ljgKgsxZC55c4pCVoD7Yx5hW3FS38U6Fx3EGXEMHJuLzrLQpbN4dfw1g0gmlOeAKAqrf37/B//nh6VZSgq2AAAAAElFTkSuQmCC"
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 58
  },
  {
   "cell_type": "markdown",
   "id": "cba82efd-a1d0-4e82-a4ff-17eff4911932",
   "metadata": {},
   "source": [
    "Another tool for exploring chemical datasets is the Bemis-Murcko scaffold. In this technique a molecule is reduced to a set of connected rings and linkers.  We can use the **GetScaffoldForMol**  method from the RDKit to generate Bemis-Murcko scaffolds.  "
   ]
  },
  {
   "cell_type": "code",
   "id": "ba564651-15f8-4df6-86a8-0b2036859241",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.071776Z",
     "start_time": "2025-05-06T01:16:07.066223Z"
    }
   },
   "source": [
    "df['Scaffold'] = df.mol.apply(GetScaffoldForMol)"
   ],
   "outputs": [],
   "execution_count": 59
  },
  {
   "cell_type": "markdown",
   "id": "8eab4d0f-6219-41e2-8640-4de321a34923",
   "metadata": {},
   "source": [
    "The generated scaffolds are RDKit molecule objects.  We would like to find the most frequently occuring scaffolds.  To do this, we need to convert the scaffolds to SMILES.  "
   ]
  },
  {
   "cell_type": "code",
   "id": "a4ddc444-1978-4289-aee2-404efae719ea",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.086551Z",
     "start_time": "2025-05-06T01:16:07.082619Z"
    }
   },
   "source": [
    "df['Scaffold_SMILES'] = df.Scaffold.apply(Chem.MolToSmiles)"
   ],
   "outputs": [],
   "execution_count": 60
  },
  {
   "cell_type": "markdown",
   "id": "27aec452-590e-461b-9638-a24433079b0a",
   "metadata": {},
   "source": [
    "Now we can use the [value_counts_df](https://useful-rdkit-utils.readthedocs.io/en/latest/pandas.html#useful_rdkit_utils.pandas_utils.value_counts_df) method in [useful_rdkit_utils](https://useful-rdkit-utils.readthedocs.io/en/latest/index.html) count how many times each scaffold is used.  "
   ]
  },
  {
   "cell_type": "code",
   "id": "be5847dd-c13a-48e1-b4d5-3c8bb9b645f1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.100441Z",
     "start_time": "2025-05-06T01:16:07.097259Z"
    }
   },
   "source": [
    "scaffold_counts_df = uru.value_counts_df(df,\"Scaffold_SMILES\")\n",
    "scaffold_counts_df.head()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "                                     Scaffold_SMILES  count\n",
       "0  O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]...     16\n",
       "1    O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1     10\n",
       "2  O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]c...      7\n",
       "3  O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(C2=CCNC2...      3\n",
       "4           O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccccc1      3"
      ],
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Scaffold_SMILES</th>\n",
       "      <th>count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]...</td>\n",
       "      <td>16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]c...</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(C2=CCNC2...</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccccc1</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 61
  },
  {
   "cell_type": "markdown",
   "id": "c5b1249e-46d1-4e69-a665-001a1d2613b4",
   "metadata": {},
   "source": [
    "Use the **scaffold_counts_df** we created above to view the scaffolds and their frequencies. "
   ]
  },
  {
   "cell_type": "code",
   "id": "05c2ac54-d6c9-4442-974d-f5442b5e50b5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.136645Z",
     "start_time": "2025-05-06T01:16:07.131130Z"
    }
   },
   "source": [
    "mols2grid.display(scaffold_counts_df,smiles_col=\"Scaffold_SMILES\",subset=[\"img\",\"count\"],size=(250,250),\n",
    "                  n_items_per_page=6)"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "MolGridWidget()"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "417f73e907354f2db666116284566667"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<style>\n",
       "    /* Some CSS to integrate with Jupyter more cleanly */\n",
       "    div.output_subarea {\n",
       "        /* Undo an unfortunate max-width parameter\n",
       "        that causes the output area to be too narrow\n",
       "        on smaller screens. */\n",
       "        max-width: none;\n",
       "\n",
       "        /* Align the table with the content */\n",
       "        padding: 0;\n",
       "\n",
       "        /* Let it breathe */\n",
       "        margin-top: 20px;\n",
       "    }\n",
       "</style>\n",
       "\n",
       "<iframe class=\"mols2grid-iframe\" frameborder=\"0\" width=\"100%\"\n",
       "    \n",
       "    \n",
       "    allow=\"clipboard-write\"\n",
       "    \n",
       "    \n",
       "    sandbox=\"allow-scripts allow-same-origin allow-downloads allow-popups allow-modals\"\n",
       "    \n",
       "    srcdoc=\"\n",
       "\n",
       "\n",
       "\n",
       "&lt;html lang=&quot;en&quot;&gt;\n",
       "    &lt;head&gt;\n",
       "        &lt;meta charset=&quot;UTF-8&quot; /&gt;\n",
       "        &lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot; /&gt;\n",
       "        &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot; /&gt;\n",
       "        &lt;title&gt;Document!&lt;/title&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;style&gt;\n",
       "            /**\n",
       " * General styling\n",
       " */\n",
       "body {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "}\n",
       "h1,h2,h3,h4 {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "h1 {\n",
       "    font-size: 26px;\n",
       "}\n",
       "h2 {\n",
       "    font-size: 20px;\n",
       "    font-weight: 400;\n",
       "}\n",
       "h3 {\n",
       "\tfont-size: 16px;\n",
       "}\n",
       "p {\n",
       "    margin: 0 0 10px 0;\n",
       "}\n",
       "\n",
       "\n",
       "/* Remove body margin inside iframe */\n",
       "body.m2g-inside-iframe {\n",
       "    margin: 0;\n",
       "}\n",
       "\n",
       "/* In-cell text */\n",
       "#mols2grid .data:not(.data-img) {\n",
       "    height: 16px;\n",
       "    line-height: 16px;\n",
       "}\n",
       "/* Text truncation */\n",
       "#mols2grid .data {\n",
       "    /* Break text into multiple lines (default for static)... */\n",
       "    word-wrap: normal;\n",
       "\n",
       "    /* ...or truncate it (default for interactive). */\n",
       "    overflow: hidden;\n",
       "    white-space: nowrap;\n",
       "    text-overflow: ellipsis;\n",
       "}\n",
       "\n",
       "\n",
       "/**\n",
       " * Popover\n",
       " * - - -\n",
       " * Note: this is a bootstrap variable which is not namespaced.\n",
       " * To avoid any contamination, we only style it when the\n",
       " * x-placement parameter is set.\n",
       " */\n",
       ".popover[x-placement] {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    background: white;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    font-size: 12px;\n",
       "    padding: 10px;\n",
       "    border-radius: 5px;\n",
       "    box-shadow: 0 0 20px rgba(0,0,0,.15);\n",
       "    user-select: none;\n",
       "}\n",
       ".popover[x-placement] h3 {\n",
       "    margin: 0;\n",
       "}\n",
       ".popover[x-placement] .arrow {\n",
       "    width: 10px;\n",
       "    height: 10px;\n",
       "    background: #fff;\n",
       "    border: solid 1px rgba(0,0,0,.2);\n",
       "    box-sizing: border-box;\n",
       "    position: absolute;\n",
       "    transform-origin: 5px 5px;\n",
       "    clip-path: polygon(0 0, 100% 0, 100% 100%);\n",
       "}\n",
       ".popover[x-placement=&#x27;left&#x27;] .arrow {\n",
       "    transform: rotate(45deg);\n",
       "    top: 50%;\n",
       "    right: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;right&#x27;] .arrow {\n",
       "    transform: rotate(-135deg);\n",
       "    top: 50%;\n",
       "    left: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;top&#x27;] .arrow {\n",
       "    transform: rotate(135deg);\n",
       "    left: 50%;\n",
       "    bottom: -5px;\n",
       "}\n",
       ".popover[x-placement=&#x27;bottom&#x27;] .arrow {\n",
       "    transform: rotate(-45deg);\n",
       "    left: 50%;\n",
       "    top: -5px;\n",
       "}\n",
       "            body {\n",
       "    /* Colors */\n",
       "    --m2g-black: rgba(0,0,0,.75);\n",
       "    --m2g-black-soft: rgba(0,0,0,.35);\n",
       "    --m2g-black-10: rgba(0,0,0,.1);\n",
       "    --m2g-bg: #f6f6f6;\n",
       "    --m2g-border: solid 1px rgba(0,0,0,0.2);\n",
       "    --m2g-hl: #555; /* Highlight color */\n",
       "    --m2g-hl-shadow: inset 0 0 0 1px var(--m2g-hl); /* Inset 1px shadow to make border thicker */\n",
       "    --m2g-blue: #0f62fe;\n",
       "    --m2g-blue-soft: rgba(15,98,254,.2);\n",
       "\n",
       "    /* Icons */\n",
       "    --m2g-icn-triangle: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;rgba(0,0,0,.75)&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-triangle-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;20&quot; fill=&quot;white&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M9.5713 13.285L6.2543 7.757C6.0543 7.424 6.2953 7 6.6823 7L13.3173 7C13.7053 7 13.9463 7.424 13.7453 7.757L10.4283 13.285C10.2343 13.609 9.7653 13.609 9.5713 13.285Z&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    --m2g-icn-cb-white: url(&#x27;data:image/svg+xml;utf8,&lt;svg width=&quot;16&quot; height=&quot;16&quot; viewBox=&quot;0 0 16 16&quot; fill=&quot;none&quot; stroke=&quot;white&quot; stroke-width=&quot;2.5&quot; stroke-linecap=&quot;round&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;&lt;path d=&quot;M4 7.65686L7 10.6569L12.6569 5.00001&quot;/&gt;&lt;/svg&gt;&#x27;);\n",
       "    \n",
       "    /* Border radius */\n",
       "    --m2g-br: 3px;\n",
       "    --m2g-br-l: var(--m2g-br) 0 0 var(--m2g-br); /* Left-only */\n",
       "    --m2g-br-r: 0 var(--m2g-br) var(--m2g-br) 0; /* Right-only */\n",
       "\n",
       "    /* Text */\n",
       "    --m2g-fs: 14px; /* UI font-size */\n",
       "    --m2g-fs-cell: 12px; /* Cell font-size */\n",
       "\n",
       "    /* Transition speeds */\n",
       "    --m2g-trans: 150ms;\n",
       "\n",
       "    /* Layout */\n",
       "    --m2g-h: 40px; /* Form element height */\n",
       "}\n",
       "\n",
       "/* Styling */\n",
       "#mols2grid {\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    font-size: var(--m2g-fs);\n",
       "}\n",
       "\n",
       "/* Fixes */\n",
       "#mols2grid *,\n",
       "#mols2grid *::before,\n",
       "#mols2grid *::after {\n",
       "    box-sizing: border-box;\n",
       "    outline: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-functions {\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row {\n",
       "    flex: 0;\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Individual elements don&#x27;t scale */\n",
       "#mols2grid .m2g-functions .m2g-row &gt; * {\n",
       "    flex: 0 0;\n",
       "    margin-right: 10px;\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-row:last-child &gt; *:last-child {\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Row 1: pagination + gap + sort */\n",
       "#mols2grid .m2g-functions .m2g-row:first-child {\n",
       "    flex: 1; /* Scale */\n",
       "}\n",
       "#mols2grid .m2g-functions .m2g-gap {\n",
       "    /* The gap in between will scale, so the pagination\n",
       "    stays on the left, while the rest moves to the right */\n",
       "    flex: 1;\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Pagination\n",
       " */\n",
       "\n",
       "#mols2grid ul.m2g-pagination {\n",
       "    /* Unset defaults */\n",
       "    list-style-type: none;\n",
       "    margin-block-start: 0;\n",
       "    margin-block-end: 0;\n",
       "    margin-inline-start: 0;\n",
       "    margin-inline-end: 0;\n",
       "    padding-inline-start: 0;\n",
       "\n",
       "    /* Custom */\n",
       "    display: flex;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li {\n",
       "    background: var(--m2g-bg) ;\n",
       "    border: var(--m2g-border);\n",
       "    height: var(--m2g-h);\n",
       "    min-width: calc(var(--m2g-h) + 1px);\n",
       "    position: relative;\n",
       "    user-select: none;\n",
       "    \n",
       "    /* Compensate for double border */\n",
       "    margin-right: -1px;\n",
       "    \n",
       "    /* Center text */\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    min-width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li a {\n",
       "    text-decoration: none;\n",
       "    color: var(--m2g-black);\n",
       "    padding: 0 10px;\n",
       "    width: 100%;\n",
       "    height: var(--m2g-h);\n",
       "    line-height: var(--m2g-h);\n",
       "    text-align: center;\n",
       "    /* Compensate for border so there&#x27;s no gap between click areas  */\n",
       "    margin: 0 -1px;\n",
       "}\n",
       "\n",
       "/* Corner shape */\n",
       "#mols2grid ul.m2g-pagination li:first-child {\n",
       "    border-radius: var(--m2g-br-l);\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li:last-child {\n",
       "    border-radius: var(--m2g-br-r);\n",
       "    margin-right: 0;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid ul.m2g-pagination li:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "    z-index: 1;\n",
       "}\n",
       "\n",
       "/* Active state */\n",
       "#mols2grid ul.m2g-pagination li.active {\n",
       "    background: var(--m2g-hl);\n",
       "    z-index: 1;\n",
       "}\n",
       "#mols2grid ul.m2g-pagination li.active a {\n",
       "    cursor: default;\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "/* Disabled sate */\n",
       "#mols2grid ul.m2g-pagination li.disabled a {\n",
       "    cursor: default;\n",
       "    color: rgba(0,0,0,.25);\n",
       "    pointer-events: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Dropdowns\n",
       " */\n",
       "\n",
       "#mols2grid ::placeholder {\n",
       "    color: var(--m2g-black-soft);\n",
       "}\n",
       "#mols2grid .m2g-dropdown {\n",
       "    height: var(--m2g-h);\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "    position: relative;\n",
       "}\n",
       "#mols2grid .m2g-dropdown select {\n",
       "    -webkit-appearance: none;\n",
       "    -moz-appearance: none;\n",
       "    -ms-appearance: none;\n",
       "    appearance: none;\n",
       "    background: transparent;\n",
       "    border: none;\n",
       "    height: 100%;\n",
       "    padding: 0 13px;\n",
       "    min-width: 0;\n",
       "    max-width: 250px;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "/* Icon */\n",
       "#mols2grid .m2g-dropdown .m2g-icon {\n",
       "    width: 30px;\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    pointer-events: none;\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg:not(.m2g-stroke) {\n",
       "    fill: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-dropdown .m2g-icon svg.m2g-stroke {\n",
       "    stroke: var(--m2g-black);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "/* We hide the native select element because\n",
       " * it is limited in styling. Instead, we display\n",
       " * the selected value in a div. */\n",
       "#mols2grid .m2g-dropdown .m2g-display {\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    right: 0;\n",
       "    top: 0;\n",
       "    bottom: 0;\n",
       "    pointer-events: none;\n",
       "    color: var(--m2g-black);\n",
       "    line-height: var(--m2g-h);\n",
       "    padding: 0 25px 0 13px;\n",
       "\n",
       "    /* Truncate dropdown text */\n",
       "    white-space: nowrap;\n",
       "\ttext-overflow: ellipsis;\n",
       "\toverflow: hidden;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Action dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-actions {\n",
       "    width: var(--m2g-h);\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions select {\n",
       "    opacity: 0;\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-actions .m2g-icon {\n",
       "    width: var(--m2g-h);\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Sort dropdown\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-dropdown.m2g-sort {\n",
       "    flex: 0 0 200px;\n",
       "    width: 200px; /* Needed in addition to flex-basis for small sizes! */\n",
       "    border-radius: var(--m2g-br);\n",
       "    background: var(--m2g-bg);\n",
       "    display: flex;\n",
       "}\n",
       "\n",
       "/* Dropdown */\n",
       "#mols2grid .m2g-dropdown.m2g-sort select {\n",
       "    flex: 1 1;\n",
       "    opacity: 0;\n",
       "    /* padding-right: 70px; Space for &quot;Sort:&quot; */\n",
       "    box-sizing: border-box;\n",
       "}\n",
       "\n",
       "/* Sort order */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-order {\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    flex: 0 0 30px;\n",
       "    height: 100%;\n",
       "    border-left: var(--m2g-border);\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort.m2d-arrow-desc .m2g-order {\n",
       "    transform: rotate(180deg);\n",
       "    border-left: none;\n",
       "    border-right: var(--m2g-border);\n",
       "}\n",
       "\n",
       "/* Display */\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display {\n",
       "    right: 31px;\n",
       "    padding-right: 13px;\n",
       "}\n",
       "#mols2grid .m2g-dropdown.m2g-sort .m2g-display::before {\n",
       "    content: &#x27;Sort: &#x27;;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-display,\n",
       "#mols2grid .m2g-dropdown.m2g-sort:focus-within .m2g-order {\n",
       "    background-color: transparent;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/*\n",
       " * Search bar\n",
       " */\n",
       "\n",
       "#mols2grid .m2g-search-wrap {\n",
       "    height: var(--m2g-h);\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: flex-end;\n",
       "    background: var(--m2g-bg);\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: var(--m2g-br);\n",
       "}\n",
       "#mols2grid .m2g-searchbar {\n",
       "    width: 170px;\n",
       "    height: var(--m2g-h);\n",
       "    padding: 0 13px;\n",
       "    border: none;\n",
       "    color: var(--m2g-black);\n",
       "    cursor: text;\n",
       "    background: transparent;\n",
       "}\n",
       "\n",
       "/* Focus state */\n",
       "#mols2grid .m2g-search-wrap:focus-within {\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Option buttons */\n",
       "#mols2grid .m2g-search-options {\n",
       "    font-size: 12px;\n",
       "    display: flex;\n",
       "    height: calc(1.5em + .75rem);\n",
       "    line-height: calc(1.5em + .75rem);\n",
       "    margin-right: 5px;\n",
       "    border-radius: var(--m2g-br);\n",
       "    color: var(--m2g-black);\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option {\n",
       "    background: var(--m2g-black-10);\n",
       "    padding: 0 13px;\n",
       "    cursor: default;\n",
       "    user-select: none;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:not(.sel) {\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:first-child {\n",
       "    border-radius: 2px 0 0 2px;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option:last-child {\n",
       "    border-radius: 0 2px 2px 0;\n",
       "}\n",
       "#mols2grid .m2g-search-options .m2g-option.sel {\n",
       "    background: var(--m2g-hl);\n",
       "    color: #fff;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#mols2grid .m2g-list {\n",
       "    display: flex;\n",
       "    flex-wrap: wrap;\n",
       "    align-items: flex-start;\n",
       "    justify-content: flex-start;\n",
       "    padding: 1px; /* Compensate for negative padding on cell */\n",
       "    user-select: none;\n",
       "    margin: 0px;\n",
       "    margin-top: 20px;\n",
       "    font-family: &#x27;DejaVu&#x27;, sans-serif;\n",
       "    \n",
       "}\n",
       "\n",
       "/* Cell */\n",
       "#mols2grid .m2g-cell {\n",
       "    border: 1px solid #cccccc;\n",
       "    text-align: center;\n",
       "    vertical-align: top;\n",
       "    font-family: var(--font-family);\n",
       "    padding: 10px;\n",
       "    padding-top: max(10px, 20px);\n",
       "    margin: -1px -1px 0 0;\n",
       "    flex: 1 0 250px;\n",
       "    position: relative;\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    cursor: pointer;\n",
       "    color: var(--m2g-black);\n",
       "    overflow: hidden;\n",
       "    box-sizing: border-box;\n",
       "    background-color: white;\n",
       "}\n",
       "#mols2grid .m2g-cell:focus {\n",
       "    z-index: 1;\n",
       "    border-color: var(--m2g-hl);\n",
       "    box-shadow: var(--m2g-hl-shadow);\n",
       "}\n",
       "\n",
       "/* Phantom cells to maintain grid structure with less results */\n",
       "#mols2grid .m2g-cell.m2g-phantom {\n",
       "    border: none;\n",
       "    pointer-events: none;\n",
       "    height: 0;\n",
       "    padding: 0;\n",
       "}\n",
       "\n",
       "/* Checkbox &amp; ID */\n",
       "#mols2grid .m2g-cb-wrap {\n",
       "    position: absolute;\n",
       "    top: 3px;\n",
       "    left: 3px;\n",
       "    display: flex;\n",
       "    border-radius: 2px;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    padding: 3px;\n",
       "    padding-right: 0;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] {\n",
       "    display: none;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .m2g-cb {\n",
       "\twidth: 16px;\n",
       "\theight: 16px;\n",
       "\tbox-sizing: border-box;\n",
       "\tbackground: #fff;\n",
       "\tborder: var(--m2g-border);\n",
       "\tborder-radius: 2px;\n",
       "    margin-right: 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox]:checked + .m2g-cb {\n",
       "    border: none;\n",
       "    background-color: var(--m2g-blue);\n",
       "    background-image: var(--m2g-icn-cb-white);\n",
       "}\n",
       "#mols2grid .m2g-tooltip {\n",
       "    /* This is a div spanning full cell size where the\n",
       "    tooltip is rendered around, because you can&#x27;t attach\n",
       "    it to the parent due to list.js limitation. */\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    position: absolute;\n",
       "    left: 0;\n",
       "    top: 0;\n",
       "    z-index: -1;\n",
       "    pointer-events: none;\n",
       "    opacity: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell:has(:checked) {\n",
       "    background: #ffd !important; /* Overrides user-set background color */\n",
       "}\n",
       "#mols2grid .data-mols2grid-id-display {\n",
       "    font-size: var(--m2g-fs-cell);\n",
       "    line-height: 16px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap input[type=checkbox] + .data-mols2grid-id-display {\n",
       "    padding: 0 5px 0 5px;\n",
       "}\n",
       "#mols2grid .m2g-cb-wrap .data-name-display {\n",
       "    font-size: var(--m2g-fs);\n",
       "    line-height: 16px;\n",
       "}\n",
       "\n",
       "/* Info + callback button wrap (28px high) */\n",
       "#mols2grid .m2g-cell-actions {\n",
       "    position: absolute;\n",
       "    top: 0;\n",
       "    right: 0;\n",
       "    display: flex;\n",
       "    flex-direction: row;\n",
       "    font-size: 0;\n",
       "    line-height: 0;\n",
       "    \n",
       "    /* background: yellow; */\n",
       "}\n",
       "\n",
       "/* Info button */\n",
       "#mols2grid .m2g-info {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    border-radius: 2px;\n",
       "    line-height: 28px;\n",
       "    font-size: min(14px, 12px);\n",
       "    font-family: Georgia, serif;\n",
       "    font-style: italic;\n",
       "    padding: 0;\n",
       "    text-align: center;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info {\n",
       "    color: #fff;\n",
       "}\n",
       "#mols2grid .m2g-keep-tooltip .m2g-info::before {\n",
       "    content: &#x27;i&#x27;;\n",
       "    width: 18px;\n",
       "    height: 18px;\n",
       "    line-height: 18px;\n",
       "    background: var(--m2g-hl);\n",
       "    position: absolute;\n",
       "    left: 5px;\n",
       "    top: 5px;\n",
       "    border-radius: 9px;\n",
       "}\n",
       "\n",
       "/* Callback button */\n",
       "#mols2grid .m2g-callback {\n",
       "    width: 28px;\n",
       "    height: 28px;\n",
       "    cursor: pointer;\n",
       "}\n",
       "#mols2grid .m2g-callback::after {\n",
       "    content: &#x27;&#x27;;\n",
       "    display: block;\n",
       "    width: 16px;\n",
       "    height: 16px;\n",
       "    margin: 6px;\n",
       "    border: var(--m2g-border);\n",
       "    border-radius: 2px;\n",
       "    background: var(--m2g-bg) var(--m2g-icn-triangle) no-repeat center;\n",
       "    transform: rotate(-90deg);\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#mols2grid .m2g-cell .data-img {\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell img,\n",
       "#mols2grid .m2g-cell svg {\n",
       "    max-width: 100%;\n",
       "    height: auto;\n",
       "    padding: 0;\n",
       "}\n",
       "#mols2grid .m2g-cell svg &gt; rect:first-child {\n",
       "    /* Remove the SVG background */\n",
       "    fill: transparent !important;\n",
       "}\n",
       "\n",
       "/* Text below image */\n",
       ".m2g-copy-blink {\n",
       "    animation: m2g-blink var(--m2g-trans) 3;\n",
       "}\n",
       "@keyframes m2g-blink {\n",
       "    0% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    49% {\n",
       "        opacity: 1;\n",
       "    }\n",
       "    50% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "    100% {\n",
       "        opacity: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* Copyable text */\n",
       ".copy-me {\n",
       "    position: relative;\n",
       "    cursor: pointer;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Modal popup\n",
       " * - - -\n",
       " * Triggered by make_popup_callback()\n",
       " * See https://mols2grid.readthedocs.io/en/latest/notebooks/callbacks.html#Display-a-popup-containing-descriptors\n",
       " */\n",
       "\n",
       "/* Container */\n",
       "#m2g-modal-container {\n",
       "    display: flex;\n",
       "    align-items: center;\n",
       "    justify-content: center;\n",
       "    background: var(--m2g-black-10);\n",
       "    position: fixed;\n",
       "    top: 0;\n",
       "    left: 0;\n",
       "    z-index: 1;\n",
       "    width: 100%;\n",
       "    height: 100%;\n",
       "    \n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transition: opacity var(--m2g-trans) linear;\n",
       "}\n",
       "\n",
       "/* Modal */\n",
       "#m2g-modal {\n",
       "    background: #fff;\n",
       "    border-radius: var(--m2g-br);\n",
       "    box-shadow: 0 0 30px var(--m2g-black-10);\n",
       "    padding: 20px;\n",
       "    position: relative;\n",
       "    max-width: calc(100% - 80px);\n",
       "    max-height: calc(100% - 80px);\n",
       "    display: flex;\n",
       "    flex-direction: column;\n",
       "    min-width: 26px;\n",
       "\n",
       "    /* Transition */\n",
       "    opacity: 0;\n",
       "    transform: translate(0, 5px);\n",
       "    transition: transform var(--m2g-trans) ease-in-out, opacity var(--m2g-trans) linear;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header {\n",
       "    flex: 0 0 26px;\n",
       "    margin-bottom: 10px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 {\n",
       "    margin-bottom: 0;\n",
       "}\n",
       "#m2g-modal .m2g-modal-header h2 + p {\n",
       "    font-size: 15px;\n",
       "}\n",
       "#m2g-modal .m2g-modal-body {\n",
       "    flex: 1;\n",
       "    position: relative;\n",
       "}\n",
       "\n",
       "/* Transition */\n",
       "#m2g-modal-container.show {\n",
       "    opacity: 1;\n",
       "}\n",
       "#m2g-modal-container.show #m2g-modal {\n",
       "    opacity: 1;\n",
       "    transform: translate(0, 0);\n",
       "}\n",
       "\n",
       "/* Header + close btn */\n",
       "#m2g-modal h2 {\n",
       "    line-height: 26px;\n",
       "    padding-right: 40px;\n",
       "    text-transform: capitalize;\n",
       "}\n",
       "#m2g-modal h3 {\n",
       "    \n",
       "}\n",
       "#m2g-modal button.close {\n",
       "    background: transparent;\n",
       "    padding: 0;\n",
       "    color: var(--m2g-black);\n",
       "    font-size: 1.5rem;\n",
       "    width: 40px;\n",
       "    height: 40px;\n",
       "    position: absolute;\n",
       "    top: 13px;\n",
       "    right: 13px;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "/* Image */\n",
       "#m2g-modal .svg-wrap svg {\n",
       "    max-width: 100%;\n",
       "    margin-bottom: 20px;\n",
       "}\n",
       "\n",
       "/* Separator */\n",
       "hr {\n",
       "    width: 100%;\n",
       "    height: 1px;\n",
       "    background: #ddd;\n",
       "    margin: 15px 0;\n",
       "    border: none;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Hover states\n",
       " */\n",
       "@media (hover:hover) {\n",
       "    /* Pagination */\n",
       "    #mols2grid ul.m2g-pagination li:not(.active):not(.disabled):hover {\n",
       "        background: #f0f0f0;\n",
       "        z-index: 1;\n",
       "    }\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        /* Keeping the hover border consiistent */\n",
       "        margin-left: 1px;\n",
       "        border-left: none;\n",
       "        min-width: 40px;\n",
       "    }\n",
       "\n",
       "    /* Dropdowns &amp; search */\n",
       "    #mols2grid .m2g-dropdown:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover,\n",
       "    #mols2grid .m2g-sort:not(:focus-within) .m2g-order:hover {\n",
       "        background-color: #f0f0f0;\n",
       "    }\n",
       "    #mols2grid .m2g-search-wrap:not(:focus-within):hover {\n",
       "        background: #fff;\n",
       "        border-color: rgba(0,0,0,.3);\n",
       "    }\n",
       "    /* Hocus pocus to have separate hover states for dropdown and arrow */\n",
       "    #mols2grid .m2g-dropdown.m2g-sort:not(:focus-within):hover .m2g-order:not(:hover) + .m2g-display {\n",
       "        background-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Search options */\n",
       "    #mols2grid .m2g-search-options .m2g-option:not(.sel):hover {\n",
       "        background: rgba(0,0,0,.15);\n",
       "    }\n",
       "\n",
       "    /* Grid */\n",
       "    /* Note: this is in an ::after pseudo element, so the transparent\n",
       "    hover color plays nice with the cell background color. */\n",
       "    #mols2grid .m2g-cell:hover::after {\n",
       "        content: &#x27;&#x27;;\n",
       "        width: 100%;\n",
       "        height: 100%;\n",
       "        position: absolute;\n",
       "        top: 0;\n",
       "        left: 0;\n",
       "        background-color: rgba(0,0,0,0.05);\n",
       "        pointer-events: none;\n",
       "    }\n",
       "\n",
       "    /* info button */\n",
       "    #mols2grid .m2g-info:hover::before {\n",
       "        content: &#x27;i&#x27;;\n",
       "        color: #fff;\n",
       "        width: 18px;\n",
       "        height: 18px;\n",
       "        line-height: 18px;\n",
       "        background: var(--m2g-hl);\n",
       "        position: absolute;\n",
       "        left: 5px;\n",
       "        top: 5px;\n",
       "        border-radius: 9px;\n",
       "    }\n",
       "    \n",
       "    /* Callback button */\n",
       "    #mols2grid .m2g-callback:hover::after {\n",
       "        background-color: var(--m2g-black);\n",
       "        background-image: var(--m2g-icn-triangle-white);\n",
       "        border-color: transparent;\n",
       "    }\n",
       "\n",
       "    /* Copyable text */\n",
       "    .copy-me:hover {\n",
       "        text-decoration: underline;\n",
       "        text-decoration-color: var(--m2g-blue);\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Responsive behavior.\n",
       " * - - -\n",
       " * Note: container queries won&#x27;t work in older browsers,\n",
       " * but this is purely aesthetical behavior so that&#x27;s ok.\n",
       " * https://caniuse.com/css-container-queries\n",
       " */\n",
       "\n",
       "/* This sets the msg-list div as reference container */\n",
       "#mols2grid {\n",
       "    container-type: inline-size;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Functions section\n",
       " */\n",
       "\n",
       "/* When there&#x27;s not enough space to put everything in one row, we break it into two.\n",
       " * - - -\n",
       " * 870px = pagination 280 + sort 200 + search 300 + menu 40 + (3*10 gap) = 850 + 20 buffer.\n",
       " * Buffer required because the button width inside the search depends on the font.\n",
       " */\n",
       "@container (max-width: 870px) {\n",
       "    #mols2grid .m2g-functions {\n",
       "        flex-direction: column-reverse;\n",
       "        gap: 10px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:last-child {\n",
       "        justify-content: flex-end;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-row:first-child *:last-child {\n",
       "        margin-right: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + sort on one row,\n",
       " * we reduce the sort drodpwon width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    #mols2grid .m2g-functions .m2g-sort {\n",
       "        width: 80px;\n",
       "        flex-basis: 80px;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display {\n",
       "        font-size: 0;\n",
       "        line-height: 0;\n",
       "        padding-right: 0;\n",
       "    }\n",
       "    #mols2grid .m2g-functions .m2g-sort .m2g-display::before {\n",
       "        content: &#x27;Sort&#x27;;\n",
       "        font-size: var(--m2g-fs);\n",
       "        line-height: var(--m2g-h);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for pagination + reduced sort on one row,\n",
       " * we reduce the pagination width.\n",
       " */\n",
       "@container (max-width: 500px) {\n",
       "    /* We&#x27;re overriding min-width from different\n",
       "    locations, including responsive rules */\n",
       "    #mols2grid ul.m2g-pagination li,\n",
       "    #mols2grid ul.m2g-pagination li:last-child,\n",
       "    #mols2grid ul.m2g-pagination li.active + li:hover {\n",
       "        min-width: 0;\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s not enough room for searchbar + menu\n",
       " * we scale down the searchbar to fit the container.\n",
       " */\n",
       "@container (max-width: 370px) {\n",
       "    #mols2grid .m2g-functions .m2g-row .m2g-search-wrap {\n",
       "        flex: 1;\n",
       "    }\n",
       "    #mols2grid .m2g-searchbar {\n",
       "        width: calc(100% - 50px);\n",
       "    }\n",
       "    #mols2grid .m2g-search-options {\n",
       "        width: 50px;\n",
       "    }\n",
       "\n",
       "    /* Collapse options in T/M buttons */\n",
       "    #mols2grid .m2g-search-options .m2g-option {\n",
       "        width: 25px;\n",
       "        text-align: center;\n",
       "        padding: 0;\n",
       "        overflow: hidden;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:first-child::before {\n",
       "        content: &#x27;T\\A&#x27;\n",
       "    }\n",
       "    #mols2grid .m2g-search-options .m2g-option:last-child::before {\n",
       "        content: &#x27;S\\A&#x27;\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Grid\n",
       " */\n",
       "\n",
       "/* When there&#x27;s room for 5 columns, fall back to 4 */\n",
       "@container (min-width: 999px) and (max-width: 1499px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 4);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 7-11 columns, fall back to 6 */\n",
       "@container (min-width: 1499px) and (max-width: 2999px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 6);\n",
       "    }\n",
       "}\n",
       "\n",
       "/* When there&#x27;s room for 13+ columns, fall back to 12 */\n",
       "@container (min-width: 2999px) {\n",
       "    #mols2grid .m2g-cell {\n",
       "        flex-basis: calc(100% / 12);\n",
       "    }\n",
       "}\n",
       "\n",
       "            /* Custom CSS */\n",
       "            \n",
       "        &lt;/style&gt;\n",
       "        &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/list.js/2.3.1/list.min.js&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot; integrity=&quot;sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "&lt;script src=&quot;https://unpkg.com/@rdkit/rdkit@2022.3.1/Code/MinimalLib/dist/RDKit_minimal.js&quot;&gt;&lt;/script&gt;\n",
       "        &lt;script&gt;\n",
       "    // Set iframe height to fit content.\n",
       "    function fitIframe(iframe) {\n",
       "        // Ignore when there&#x27;s no iframe\n",
       "        if (!iframe) return\n",
       "\n",
       "        // Only fit height when no specific height was given.\n",
       "        if (iframe.getAttribute(&#x27;height&#x27;)) return;\n",
       "\n",
       "        // Initial fit + refit whenever the window width changes.\n",
       "        _fit()\n",
       "        $(window).on(&#x27;resize&#x27;, function() {\n",
       "            if (window.innerWidth != window.prevInnerWidth) {\n",
       "                window.prevInnerWidth = window.innerWidth\n",
       "                _fit();\n",
       "            }\n",
       "        })\n",
       "\n",
       "        // Fit iframe height to content height.\n",
       "        function _fit() {\n",
       "            var height = iframe.contentDocument.body.scrollHeight + 18 + &#x27;px&#x27;;\n",
       "            iframe.style.height = height;\n",
       "        }\n",
       "    }\n",
       "&lt;/script&gt;\n",
       "\n",
       "&lt;!-- prettier-ignore --&gt;\n",
       "&lt;script src=&quot;https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js&quot; integrity=&quot;sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns&quot; crossorigin=&quot;anonymous&quot;&gt;&lt;/script&gt;\n",
       "        \n",
       "        &lt;!-- Custom header --&gt;\n",
       "        \n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/head&gt;\n",
       "    &lt;body class=&quot;m2g-inside-iframe&quot;&gt;\n",
       "\n",
       "\n",
       "\n",
       "        &lt;div id=&quot;mols2grid&quot; class=&quot;grid-default&quot;&gt;\n",
       "            &lt;!-- Pagination &amp; search --&gt;\n",
       "            &lt;div class=&quot;m2g-functions&quot;&gt;\n",
       "                \n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Pagination --&gt;\n",
       "                    &lt;ul class=&quot;m2g-pagination&quot; class=&quot;d-flex&quot;&gt;&lt;/ul&gt;\n",
       "                    &lt;div class=&quot;m2g-gap&quot;&gt;&lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Sort dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-sort&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;mols2grid-id&quot; selected&gt;Index&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                                \n",
       "                                \n",
       "                                \n",
       "                            &lt;option value=&quot;data-count&quot;&gt;count&lt;/option&gt;\n",
       "                                \n",
       "                            \n",
       "                            \n",
       "                            &lt;option value=&quot;checkbox&quot;&gt;Selected&lt;/option&gt;\n",
       "                            \n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-order&quot;&gt;&lt;/div&gt;\n",
       "                        &lt;div class=&quot;m2g-display&quot;&gt;\n",
       "                            Index\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "                &lt;div class=&quot;m2g-row&quot;&gt;\n",
       "                    &lt;!-- Search bar --&gt;\n",
       "                    &lt;div class=&quot;m2g-search-wrap&quot;&gt;\n",
       "                        &lt;input\n",
       "                            type=&quot;text&quot;\n",
       "                            class=&quot;m2g-searchbar form-control&quot;\n",
       "                            placeholder=&quot;Search&quot;\n",
       "                            aria-label=&quot;Search&quot;\n",
       "                            aria-describedby=&quot;basic-addon1&quot;\n",
       "                        /&gt;\n",
       "                        &lt;div class=&quot;m2g-search-options&quot;&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-text sel&quot;&gt;Text&lt;/div&gt;\n",
       "                            &lt;div class=&quot;m2g-option m2g-search-smarts&quot;&gt;SMARTS&lt;/div&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "\n",
       "                    &lt;!-- Action dropdown --&gt;\n",
       "                    &lt;div class=&quot;m2g-dropdown m2g-actions&quot;&gt;\n",
       "                        &lt;select&gt;\n",
       "                            &lt;option hidden&gt;-&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-all&quot;&gt;Select all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;select-matching&quot;&gt;Select matching&lt;/option&gt;\n",
       "                            &lt;option value=&quot;unselect-all&quot;&gt;Unselect all&lt;/option&gt;\n",
       "                            &lt;option value=&quot;invert&quot;&gt;Invert&lt;/option&gt;\n",
       "                            &lt;option value=&quot;copy&quot;&gt;Copy to clipboard&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-smiles&quot;&gt;Save SMILES&lt;/option&gt;\n",
       "                            &lt;option value=&quot;save-csv&quot;&gt;Save CSV&lt;/option&gt;\n",
       "                        &lt;/select&gt;\n",
       "                        &lt;div class=&quot;m2g-icon&quot;&gt;\n",
       "                            &lt;svg width=&quot;20&quot; height=&quot;20&quot; viewBox=&quot;0 0 20 20&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;\n",
       "                                &lt;path d=&quot;M11.5 4C11.5 4.82843 10.8284 5.5 10 5.5C9.17157 5.5 8.5 4.82843 8.5 4C8.5 3.17157 9.17157 2.5 10 2.5C10.8284 2.5 11.5 3.17157 11.5 4ZM11.5 10C11.5 10.8284 10.8284 11.5 10 11.5C9.17157 11.5 8.5 10.8284 8.5 10C8.5 9.17157 9.17157 8.5 10 8.5C10.8284 8.5 11.5 9.17157 11.5 10ZM10 17.5C10.8284 17.5 11.5 16.8284 11.5 16C11.5 15.1716 10.8284 14.5 10 14.5C9.17157 14.5 8.5 15.1716 8.5 16C8.5 16.8284 9.17157 17.5 10 17.5Z&quot;/&gt;\n",
       "                            &lt;/svg&gt;\n",
       "                        &lt;/div&gt;\n",
       "                    &lt;/div&gt;\n",
       "                &lt;/div&gt;\n",
       "            &lt;/div&gt;\n",
       "\n",
       "            &lt;!-- Grid --&gt;\n",
       "            \n",
       "            &lt;div class=&quot;m2g-list&quot;&gt;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-count copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Scaffold_SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;\n",
       "        &lt;/div&gt;\n",
       "        &lt;script&gt;\n",
       "            // list.js\n",
       "var listObj = new List(&#x27;mols2grid&#x27;, {\n",
       "    listClass: &#x27;m2g-list&#x27;,\n",
       "    valueNames: [{data: [&#x27;mols2grid-id&#x27;]}, &#x27;data-mols2grid-id&#x27;, &#x27;data-img&#x27;, &#x27;data-Scaffold_SMILES&#x27;, &#x27;data-count&#x27;, &#x27;data-mols2grid-id-display&#x27;],\n",
       "    item: &#x27;&lt;div class=&quot;m2g-cell&quot; data-mols2grid-id=&quot;0&quot; tabindex=&quot;0&quot;&gt;&lt;div class=&quot;m2g-cb-wrap&quot;&gt;&lt;input type=&quot;checkbox&quot; tabindex=&quot;-1&quot; class=&quot;position-relative float-left cached_checkbox&quot;&gt;&lt;div class=&quot;m2g-cb&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data-mols2grid-id-display&quot;&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&quot;m2g-cell-actions&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-img copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-count copy-me&quot;&gt;&lt;/div&gt;&lt;div class=&quot;data data-Scaffold_SMILES copy-me&quot; style=&quot;display: none;&quot;&gt;&lt;/div&gt;&lt;/div&gt;&#x27;,\n",
       "    page: 6,\n",
       "    pagination: {\n",
       "        paginationClass: &quot;m2g-pagination&quot;,\n",
       "        item: &#x27;&lt;li class=&quot;page-item&quot;&gt;&lt;a class=&quot;page page-link&quot; href=&quot;#&quot; onclick=&quot;event.preventDefault()&quot;&gt;&lt;/a&gt;&lt;/li&gt;&#x27;,\n",
       "        innerWindow: 1,\n",
       "        outerWindow: 1,\n",
       "    },\n",
       "});\n",
       "listObj.remove(&quot;mols2grid-id&quot;, &quot;0&quot;);\n",
       "listObj.add([{&quot;mols2grid-id&quot;: 0, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 16, &quot;data-mols2grid-id-display&quot;: 0}, {&quot;mols2grid-id&quot;: 1, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 10, &quot;data-mols2grid-id-display&quot;: 1}, {&quot;mols2grid-id&quot;: 2, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 7, &quot;data-mols2grid-id-display&quot;: 2}, {&quot;mols2grid-id&quot;: 3, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(C2=CCNC2)cc1&quot;, &quot;data-count&quot;: 3, &quot;data-mols2grid-id-display&quot;: 3}, {&quot;mols2grid-id&quot;: 4, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccccc1&quot;, &quot;data-count&quot;: 3, &quot;data-mols2grid-id-display&quot;: 4}, {&quot;mols2grid-id&quot;: 5, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1cccnc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 3, &quot;data-mols2grid-id-display&quot;: 5}, {&quot;mols2grid-id&quot;: 6, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc(C2CC2)c1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 2, &quot;data-mols2grid-id-display&quot;: 6}, {&quot;mols2grid-id&quot;: 7, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 2, &quot;data-mols2grid-id-display&quot;: 7}, {&quot;mols2grid-id&quot;: 8, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nnc2cccnn12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 2, &quot;data-mols2grid-id-display&quot;: 8}, {&quot;mols2grid-id&quot;: 9, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2cn[nH]c2)cc1&quot;, &quot;data-count&quot;: 2, &quot;data-mols2grid-id-display&quot;: 9}, {&quot;mols2grid-id&quot;: 10, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnn1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 2, &quot;data-mols2grid-id-display&quot;: 10}, {&quot;mols2grid-id&quot;: 11, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cnccn1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 11}, {&quot;mols2grid-id&quot;: 12, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1cccnc1)c1ccc(C2=CCNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 12}, {&quot;mols2grid-id&quot;: 13, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 13}, {&quot;mols2grid-id&quot;: 14, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc(C2CC2)c1)N(Cc1ccccc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 14}, {&quot;mols2grid-id&quot;: 15, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 15}, {&quot;mols2grid-id&quot;: 16, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnc1)N(Cc1cccnc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 16}, {&quot;mols2grid-id&quot;: 17, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nncc2ccccc12)N(Cc1ccccc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 17}, {&quot;mols2grid-id&quot;: 18, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1cccnc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 18}, {&quot;mols2grid-id&quot;: 19, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C1Nc2ccccc2C1CC(=O)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 19}, {&quot;mols2grid-id&quot;: 20, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1nnc2ccccn12)Nc1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 20}, {&quot;mols2grid-id&quot;: 21, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C1NC(CC(=O)N(Cc2ccccc2)c2ccc(-c3c[nH]cn3)cc2)c2ccccc21&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 21}, {&quot;mols2grid-id&quot;: 22, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1noc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 22}, {&quot;mols2grid-id&quot;: 23, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 23}, {&quot;mols2grid-id&quot;: 24, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2cn[nH]c2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 24}, {&quot;mols2grid-id&quot;: 25, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)Nc1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 25}, {&quot;mols2grid-id&quot;: 26, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C1CN(c2ccc(N(Cc3ccccc3)C(=O)Cc3cncc4ccccc34)cc2)CCN1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 26}, {&quot;mols2grid-id&quot;: 27, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C1CNCCN1c1ccc(N(Cc2ccccc2)C(=O)Cc2cncc3ccccc23)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 27}, {&quot;mols2grid-id&quot;: 28, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cn1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 28}, {&quot;mols2grid-id&quot;: 29, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 29}, {&quot;mols2grid-id&quot;: 30, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnn1)N(Cc1ccccc1)c1ccc(-c2cn[nH]c2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 30}, {&quot;mols2grid-id&quot;: 31, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cnccn1)N(Cc1ccccc1)c1ccc(-c2cn[nH]c2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 31}, {&quot;mols2grid-id&quot;: 32, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2cn[nH]c2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 32}, {&quot;mols2grid-id&quot;: 33, &quot;data-img&quot;: null, &quot;data-Scaffold_SMILES&quot;: &quot;O=C(Cc1cccnc1)N(Cc1cccnc1)c1ccc(C2CNC2)cc1&quot;, &quot;data-count&quot;: 1, &quot;data-mols2grid-id-display&quot;: 33}]);\n",
       "\n",
       "\n",
       "// filter\n",
       "if (window.parent.mols2grid_lists === undefined) {\n",
       "    window.parent.mols2grid_lists = {};\n",
       "}\n",
       "window.parent.mols2grid_lists[&quot;default&quot;] = listObj;\n",
       "\n",
       "\n",
       "// selection\n",
       "class MolStorage extends Map {\n",
       "    multi_set(_id, _smiles) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.set(_id[i], _smiles[i])\n",
       "        }\n",
       "    }\n",
       "    multi_del(_id) {\n",
       "        for (let i = 0; i &lt; _id.length; i++) {\n",
       "            this.delete(_id[i])\n",
       "        }\n",
       "    }\n",
       "    to_dict() {\n",
       "        var content = &#x27;{&#x27;\n",
       "        for (let [key, value] of this) {\n",
       "            content += key + &#x27;:&#x27; + JSON.stringify(value) + &#x27;,&#x27;\n",
       "        }\n",
       "        content = content.length &gt; 1 ? content.slice(0, -1) : content\n",
       "        content += &#x27;}&#x27;\n",
       "        return content\n",
       "    }\n",
       "    to_keys() {\n",
       "        var content = []\n",
       "        for (let [key] of this) {\n",
       "            content.push(key)\n",
       "        }\n",
       "        return content\n",
       "    }\n",
       "    download_smi(fileName, allItems) {\n",
       "        var content = &#x27;&#x27;\n",
       "\n",
       "        if (allItems) {\n",
       "            // Gather all smiles\n",
       "            for (var item of allItems) {\n",
       "                var smiles = item.values()[&#x27;data-SMILES&#x27;]\n",
       "                var id = item.values()[&#x27;mols2grid-id&#x27;]\n",
       "                content += smiles + &#x27; &#x27; + id + &#x27;\\n&#x27;\n",
       "            }\n",
       "        } else {\n",
       "            // Gather selected smiles\n",
       "            for (let [key, value] of this) {\n",
       "                content += value + &#x27; &#x27; + key + &#x27;\\n&#x27;\n",
       "            }\n",
       "        }\n",
       "\n",
       "        var a = document.createElement(&#x27;a&#x27;)\n",
       "        var file = new Blob([content], { type: &#x27;text/plain&#x27; })\n",
       "        a.href = URL.createObjectURL(file)\n",
       "        a.download = fileName\n",
       "        a.click()\n",
       "        a.remove()\n",
       "    }\n",
       "}\n",
       "var SELECTION = new MolStorage();\n",
       "\n",
       "\n",
       "\n",
       "// kernel\n",
       "function add_selection(grid_id, _id, smiles) {\n",
       "    SELECTION.multi_set(_id, smiles);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "function del_selection(grid_id, _id) {\n",
       "    SELECTION.multi_del(_id);\n",
       "    let model = window.parent[&quot;_MOLS2GRID_&quot; + grid_id];\n",
       "    if (model) {\n",
       "        model.set(&quot;selection&quot;, SELECTION.to_dict());\n",
       "        model.save_changes();\n",
       "    }\n",
       "}\n",
       "if (window.parent.IPython !== undefined) {\n",
       "    // Jupyter notebook\n",
       "    var kernel_env = &quot;jupyter&quot;;\n",
       "} else if (window.parent.google !== undefined) {\n",
       "    // Google colab\n",
       "    var kernel_env = &quot;colab&quot;;\n",
       "} else {\n",
       "    var kernel_env = null;\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// sort\n",
       "var sortField = &#x27;mols2grid-id&#x27;\n",
       "var sortOrder = &#x27;asc&#x27;\n",
       "\n",
       "// Sort dropdown\n",
       "$(&#x27;#mols2grid .m2g-sort select&#x27;).change(sort)\n",
       "\n",
       "// Sort order\n",
       "$(&#x27;#mols2grid .m2g-order&#x27;).click(flipSort)\n",
       "\n",
       "function sort(e) {\n",
       "    if (e) {\n",
       "        sortField = e.target.value\n",
       "        var selectedOption = e.target.options[e.target.selectedIndex]\n",
       "        var sortFieldDisplay = selectedOption.text\n",
       "    }\n",
       "\n",
       "    // Sort\n",
       "    if (sortField == &#x27;checkbox&#x27;) {\n",
       "        listObj.sort(&#x27;mols2grid-id&#x27;, {order: sortOrder, sortFunction: checkboxSort})\n",
       "    } else {\n",
       "        listObj.sort(sortField, {order: sortOrder, sortFunction: mols2gridSortFunction})\n",
       "    }\n",
       "\n",
       "    // Update UI.\n",
       "    $(this).parent().find(&#x27;.m2g-display&#x27;).text(sortFieldDisplay)\n",
       "}\n",
       "\n",
       "// prettier-ignore\n",
       "function flipSort() {\n",
       "    $(this).parent().removeClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sortOrder = sortOrder === &#x27;desc&#x27; ? &#x27;asc&#x27; : &#x27;desc&#x27;\n",
       "    $(this).parent().addClass(&#x27;m2d-arrow-&#x27; + sortOrder)\n",
       "    sort()\n",
       "}\n",
       "\n",
       "function mols2gridSortFunction(itemA, itemB, options) {\n",
       "    var x = itemA.values()[options.valueName]\n",
       "    var y = itemB.values()[options.valueName]\n",
       "    if (typeof x === &#x27;number&#x27;) {\n",
       "        if (isFinite(x - y)) {\n",
       "            return x - y\n",
       "        } else {\n",
       "            return isFinite(x) ? -1 : 1\n",
       "        }\n",
       "    } else {\n",
       "        x = x ? x.toLowerCase() : x\n",
       "        y = y ? y.toLowerCase() : y\n",
       "        return x &lt; y ? -1 : x &gt; y ? 1 : 0\n",
       "    }\n",
       "}\n",
       "function checkboxSort(itemA, itemB, options) {\n",
       "    if (itemA.elm !== undefined) {\n",
       "        var checkedA = itemA.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "        if (itemB.elm !== undefined) {\n",
       "            var checkedB = itemB.elm.querySelector(&#x27;input[type=checkbox]&#x27;).checked\n",
       "            if (checkedA &amp;&amp; !checkedB) {\n",
       "                return -1\n",
       "            } else if (!checkedA &amp;&amp; checkedB) {\n",
       "                return 1\n",
       "            } else {\n",
       "                return 0\n",
       "            }\n",
       "        } else {\n",
       "            return -1\n",
       "        }\n",
       "    } else if (itemB.elm !== undefined) {\n",
       "        return 1\n",
       "    } else {\n",
       "        return 0\n",
       "    }\n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "// grid interactions (select, click, tooltip, key events)\n",
       "// Check if selection UI is supported.\n",
       "var supportSelection = eval(&#x27;True&#x27;.toLowerCase());\n",
       "\n",
       "listObj.on(&quot;updated&quot;, initInteraction);\n",
       "\n",
       "// (Re)initialiuze all grid interaction every time the grid changes.\n",
       "function initInteraction(list) {\n",
       "    initCellClick()\n",
       "    initToolTip()\n",
       "    initKeyboard()\n",
       "    if (supportSelection) initCheckbox()\n",
       "\n",
       "\n",
       "    // Hide pagination if there is only one page.\n",
       "    if (listObj.matchingItems.length &lt;= listObj.page) {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).hide()\n",
       "    } else {\n",
       "        $(&#x27;#mols2grid .m2g-pagination&#x27;).show()\n",
       "    }\n",
       "\n",
       "    // Add a bunch of phantom cells.\n",
       "    // These are used as filler to make sure that\n",
       "    // no grid cells need to be resized when there&#x27;s\n",
       "    // not enough results to fill the row.\n",
       "    $(&#x27;#mols2grid .m2g-list&#x27;).append(&#x27;&lt;div class=&quot;m2g-cell m2g-phantom&quot;&gt;&lt;/div&gt;&#x27;.repeat(11));\n",
       "}\n",
       "\n",
       "// Cell click handler.\n",
       "function initCellClick() {\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;click&#x27;).click(function(e) {\n",
       "        if ($(e.target).hasClass(&#x27;m2g-info&#x27;) || $(e.target).is(&#x27;:checkbox&#x27;)) {\n",
       "            // Info button / Checkbox --&gt; do nothing.\n",
       "        } else if ($(e.target).is(&#x27;div&#x27;) &amp;&amp; $(e.target).hasClass(&#x27;data&#x27;)) {\n",
       "            // Data string --&gt; copy text.\n",
       "            copyOnClick(e.target)\n",
       "        } else if ($(e.target).hasClass(&#x27;m2g-callback&#x27;)) {\n",
       "            // Callback button.\n",
       "            onCallbackButtonClick(e.target)\n",
       "        } else {\n",
       "            // Outside checkbox --&gt; toggle the checkbox.\n",
       "            if (supportSelection) {\n",
       "                var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "                chkbox.checked = !chkbox.checked\n",
       "                $(chkbox).trigger(&#x27;change&#x27;)\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Store an element&#x27;s text content in the clipboard.\n",
       "function copyOnClick(target) {\n",
       "    var text = $(target).text()\n",
       "    navigator.clipboard.writeText(text)\n",
       "\n",
       "    // Blink the cell to indicate that the text was copied.\n",
       "    $(target).addClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    setTimeout(function() {\n",
       "        $(target).removeClass(&#x27;m2g-copy-blink&#x27;)\n",
       "    }, 450)\n",
       "}\n",
       "\n",
       "// Keyboard actions.\n",
       "function initKeyboard() {\n",
       "    // Disable scroll when pressing UP/DOWN arrows\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keydown&#x27;).keydown(function(e) {\n",
       "        if (e.which == 38 || e.which == 40) {\n",
       "            e.preventDefault()\n",
       "        }\n",
       "    })\n",
       "\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).off(&#x27;keyup&#x27;).keyup(function(e) {\n",
       "        var chkbox = $(this).find(&#x27;input:checkbox&#x27;)[0]\n",
       "        if (e.which == 13) {\n",
       "            // ENTER: toggle\n",
       "            chkbox.checked = !chkbox.checked\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 27 || e.which == 8) {\n",
       "            // ESC/BACKSPACE: unselect\n",
       "            chkbox.checked = false\n",
       "            $(chkbox).trigger(&#x27;change&#x27;)\n",
       "        } else if (e.which == 37) {\n",
       "            // LEFT\n",
       "            $(this).prev().focus()\n",
       "        } else if (e.which == 39) {\n",
       "            // RIGHT\n",
       "            $(this).next().focus()\n",
       "        } else if (e.which == 38 || e.which == 40) {\n",
       "            var containerWidth = $(this).parent().outerWidth()\n",
       "            var cellWidth = $(this).outerWidth() + parseInt($(this).css(&#x27;marginLeft&#x27;)) * 2\n",
       "            var columns = Math.round(containerWidth / cellWidth)\n",
       "            var index = $(this).index()\n",
       "            if (e.which == 38) {\n",
       "                // UP\n",
       "                var indexAbove = Math.max(index - columns, 0)\n",
       "                $(this).parent().children().eq(indexAbove).focus()\n",
       "            } else if (e.which == 40) {\n",
       "                // DOWN    \n",
       "                var total = $(this).parent().children().length\n",
       "                var indexBelow = Math.min(index + columns, total)\n",
       "                $(this).parent().children().eq(indexBelow).focus()\n",
       "            }\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Show tooltip when hovering the info icon.\n",
       "function initToolTip() {\n",
       "    $(&#x27;#mols2grid .m2g-info&#x27;).off(&#x27;mouseenter&#x27;).off(&#x27;mouseleave&#x27;).off(&#x27;click&#x27;).mouseenter(function() {\n",
       "        // Show on enter\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        $(&#x27;body &gt; .popover&#x27;).click(function(e) {\n",
       "            if ($(e.target).hasClass(&#x27;copy-me&#x27;)) {\n",
       "                copyOnClick(e.target)\n",
       "            } else if ($(e.target).is(&#x27;button&#x27;)) {\n",
       "                \n",
       "            }\n",
       "        })\n",
       "    }).mouseleave(function() {\n",
       "        // Hide on leave, unless sticky.\n",
       "        if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    }).click(function() {\n",
       "        // Toggle sticky on click.\n",
       "        $(this).closest(&#x27;.m2g-cell&#x27;).toggleClass(&#x27;m2g-keep-tooltip&#x27;)\n",
       "\n",
       "        // Hide tooltip when sticky was turned off.\n",
       "        if ($(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;show&#x27;)\n",
       "        } else if (!$(this).closest(&#x27;.m2g-cell&#x27;).hasClass(&#x27;m2g-keep-tooltip&#x27;)) {\n",
       "            $(this).closest(&#x27;.m2g-cell&#x27;).find(&#x27;.m2g-tooltip[data-toggle=&quot;popover&quot;]&#x27;).popover(&#x27;hide&#x27;)\n",
       "        }\n",
       "    })\n",
       "}\n",
       "\n",
       "// Update selection on checkbox click.\n",
       "function initCheckbox() {\n",
       "    $(&quot;input:checkbox&quot;).off(&#x27;change&#x27;).change(function() {\n",
       "        var _id = parseInt($(this).closest(&quot;.m2g-cell&quot;).attr(&quot;data-mols2grid-id&quot;));\n",
       "        if (this.checked) {\n",
       "            var _smiles = $($(this).closest(&quot;.m2g-cell&quot;).children(&quot;.data-Scaffold_SMILES&quot;)[0]).text();\n",
       "            add_selection(&quot;default&quot;, [_id], [_smiles]);\n",
       "        } else {\n",
       "            del_selection(&quot;default&quot;, [_id]);\n",
       "        }\n",
       "    });\n",
       "}\n",
       "\n",
       "// Callback button\n",
       "function onCallbackButtonClick(target) {\n",
       "    var data = {}\n",
       "    data[&quot;mols2grid-id&quot;] = parseInt($(target).closest(&quot;.m2g-cell&quot;)\n",
       "                                            .attr(&quot;data-mols2grid-id&quot;));\n",
       "    data[&quot;img&quot;] = $(target).parent().siblings(&quot;.data-img&quot;).eq(0).get(0).innerHTML;\n",
       "    $(target).parent().siblings(&quot;.data&quot;).not(&quot;.data-img&quot;).each(function() {\n",
       "        let name = this.className.split(&quot; &quot;)\n",
       "            .filter(cls =&gt; cls.startsWith(&quot;data-&quot;))[0]\n",
       "            .substring(5);\n",
       "        data[name] = this.innerHTML;\n",
       "    });\n",
       "\n",
       "    \n",
       "    // Call custom js callback.\n",
       "    None\n",
       "    \n",
       "}\n",
       "\n",
       "\n",
       "\n",
       "/**\n",
       " * Actions\n",
       " */\n",
       "\n",
       "// Listen to action dropdown.\n",
       "$(&#x27;#mols2grid .m2g-actions select&#x27;).change(function(e) {\n",
       "    var val = e.target.value\n",
       "    switch(val) {\n",
       "        case &#x27;select-all&#x27;:\n",
       "            selectAll()\n",
       "            break\n",
       "        case &#x27;select-matching&#x27;:\n",
       "            selectMatching()\n",
       "            break\n",
       "        case &#x27;unselect-all&#x27;:\n",
       "            unselectAll()\n",
       "            break\n",
       "        case &#x27;invert&#x27;:\n",
       "            invertSelection()\n",
       "            break\n",
       "        case &#x27;copy&#x27;:\n",
       "            copy()\n",
       "            break\n",
       "        case &#x27;save-smiles&#x27;:\n",
       "            saveSmiles()\n",
       "            break\n",
       "        case &#x27;save-csv&#x27;:\n",
       "            saveCSV()\n",
       "            break\n",
       "    }\n",
       "    $(this).val(&#x27;&#x27;) // Reset dropdown\n",
       "})\n",
       "\n",
       "// Check all.\n",
       "function selectAll(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-Scaffold_SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "\n",
       "// Check matching.\n",
       "function selectMatching(e) {\n",
       "    var _id = [];\n",
       "    var _smiles = [];\n",
       "    listObj.matchingItems.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = true;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        _smiles.push(item.values()[&quot;data-Scaffold_SMILES&quot;]);\n",
       "    });\n",
       "    add_selection(&quot;default&quot;, _id, _smiles);\n",
       "};\n",
       "\n",
       "// Uncheck all.\n",
       "function unselectAll(e) {\n",
       "    var _id = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "        } else {\n",
       "            item.show()\n",
       "            item.elm.getElementsByTagName(&quot;input&quot;)[0].checked = false;\n",
       "            item.hide()\n",
       "        }\n",
       "        _id.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id);\n",
       "};\n",
       "\n",
       "// Invert selection.\n",
       "function invertSelection(e) {\n",
       "    var _id_add = [];\n",
       "    var _id_del = [];\n",
       "    var _smiles = [];\n",
       "    listObj.items.forEach(function (item) {\n",
       "        if (item.elm) {\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "        } else {\n",
       "            item.show()\n",
       "            var chkbox = item.elm.getElementsByTagName(&quot;input&quot;)[0]\n",
       "            chkbox.checked = !chkbox.checked;\n",
       "            item.hide()\n",
       "        }\n",
       "        if (chkbox.checked) {\n",
       "            _id_add.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "            _smiles.push(item.values()[&quot;data-Scaffold_SMILES&quot;]);\n",
       "        } else {\n",
       "            _id_del.push(item.values()[&quot;mols2grid-id&quot;]);\n",
       "        }\n",
       "    });\n",
       "    del_selection(&quot;default&quot;, _id_del);\n",
       "    add_selection(&quot;default&quot;, _id_add, _smiles);\n",
       "};\n",
       "\n",
       "// Copy to clipboard.\n",
       "function copy(e) {\n",
       "    // navigator.clipboard.writeText(SELECTION.to_dict());\n",
       "    content = _renderCSV(&#x27;\\t&#x27;)\n",
       "    navigator.clipboard.writeText(content)\n",
       "};\n",
       "\n",
       "// Export smiles.\n",
       "function saveSmiles(e) {\n",
       "    var fileName = &quot;selection.smi&quot;\n",
       "    if (SELECTION.size) {\n",
       "        // Download selected smiles\n",
       "        SELECTION.download_smi(fileName);\n",
       "    } else {\n",
       "        // Download all smiles\n",
       "        SELECTION.download_smi(fileName, listObj.items);\n",
       "    }\n",
       "};\n",
       "\n",
       "// Export CSV.\n",
       "function saveCSV(e) {\n",
       "    content = _renderCSV(&#x27;;&#x27;)\n",
       "    var a = document.createElement(&quot;a&quot;);\n",
       "    var file = new Blob([content], {type: &quot;text/csv&quot;});\n",
       "    a.href = URL.createObjectURL(file);\n",
       "    a.download = &quot;selection.csv&quot;;\n",
       "    a.click();\n",
       "    a.remove();\n",
       "};\n",
       "\n",
       "// Render CSV for export of clipboard.\n",
       "function _renderCSV(sep) {\n",
       "    // Same order as subset + tooltip\n",
       "    var columns = Array.from(listObj.items[0].elm.querySelectorAll(&quot;div.data&quot;))\n",
       "        .map(elm =&gt; elm.classList[1])\n",
       "        .filter(name =&gt; name !== &quot;data-img&quot;);\n",
       "    // Remove &#x27;data-&#x27; and img\n",
       "    var header = columns.map(name =&gt; name.slice(5));\n",
       "    // CSV content\n",
       "    header = [&quot;index&quot;].concat(header).join(sep);\n",
       "    var content = header + &quot;\\n&quot;;\n",
       "    listObj.items.forEach(function (item) {\n",
       "        let data = item.values();\n",
       "        let index = data[&quot;mols2grid-id&quot;];\n",
       "        if (SELECTION.has(index) || SELECTION.size === 0) {\n",
       "            content += index;\n",
       "            columns.forEach((key) =&gt; {\n",
       "                content += sep + data[key];\n",
       "            })\n",
       "            content += &quot;\\n&quot;;\n",
       "        }\n",
       "    });\n",
       "    return content\n",
       "}\n",
       "\n",
       "\n",
       "// generate images for the currently displayed molecules\n",
       "var draw_opts = {&quot;width&quot;: 250, &quot;height&quot;: 250};\n",
       "var json_draw_opts = JSON.stringify(draw_opts);\n",
       "\n",
       "var smarts_matches = {};\n",
       "\n",
       "// Load RDKit\n",
       "window\n",
       ".initRDKitModule()\n",
       ".then(function(RDKit) {\n",
       "    console.log(&#x27;RDKit version: &#x27;, RDKit.version());\n",
       "    window.RDKit = RDKit;\n",
       "    window.RDKitModule = RDKit;\n",
       "\n",
       "    // Searchbar\n",
       "    function SmartsSearch(query, columns) {\n",
       "    var smiles_col = columns[0];\n",
       "    smarts_matches = {};\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var qmol = RDKit.get_qmol(query);\n",
       "    if (qmol.is_valid()) {\n",
       "        listObj.items.forEach(function (item) {\n",
       "            var smiles = item.values()[smiles_col]\n",
       "            var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "            if (mol.is_valid()) {\n",
       "                var results = mol.get_substruct_matches(qmol);\n",
       "                if (results === &quot;\\{\\}&quot;) {\n",
       "                    item.found = false;\n",
       "                } else {\n",
       "                    item.found = true;\n",
       "                    \n",
       "                    results = JSON.parse(results);\n",
       "                    \n",
       "                    var highlights = {&quot;atoms&quot;: [], &quot;bonds&quot;: []};\n",
       "                    results.forEach(function (match) {\n",
       "                        highlights[&quot;atoms&quot;].push(...match.atoms)\n",
       "                        highlights[&quot;bonds&quot;].push(...match.bonds)\n",
       "                    });\n",
       "                    \n",
       "                    var index = item.values()[&quot;mols2grid-id&quot;];\n",
       "                    smarts_matches[index] = highlights;\n",
       "                    \n",
       "                }\n",
       "            } else {\n",
       "                item.found = false;\n",
       "            }\n",
       "            mol.delete();\n",
       "        });\n",
       "    }\n",
       "    qmol.delete();\n",
       "}\n",
       "var search_type = &quot;Text&quot;;\n",
       "// Temporary fix for regex characters being escaped by list.js\n",
       "// This extends String.replace to ignore the regex pattern used by list.js and returns\n",
       "// the string unmodified. Other calls should not be affected, unless they use the exact\n",
       "// same pattern and replacement value.\n",
       "// TODO: remove once the issue is fixed in list.js and released\n",
       "String.prototype.replace = (function(_super) {\n",
       "    return function() {\n",
       "        if (\n",
       "            (arguments[0].toString() === &#x27;/[-[\\\\]{}()*+?.,\\\\\\\\^$|#]/g&#x27;)\n",
       "            &amp;&amp; (arguments[1] === &#x27;\\\\$&amp;&#x27;)\n",
       "        ) {\n",
       "            if (this.length === 0) {\n",
       "                return &#x27;&#x27;\n",
       "            }\n",
       "            return this\n",
       "        }\n",
       "        return _super.apply(this, arguments);\n",
       "    };         \n",
       "})(String.prototype.replace);\n",
       "\n",
       "// Switch search type (Text or SMARTS)\n",
       "$(&#x27;#mols2grid .m2g-search-options .m2g-option&#x27;).click(function() {\n",
       "    search_type = $(this).text();\n",
       "    $(&#x27;#mols2grid .m2g-search-options .m2g-option.sel&#x27;).removeClass(&quot;sel&quot;);\n",
       "    $(this).addClass(&quot;sel&quot;);\n",
       "});\n",
       "\n",
       "// Searchbar update event handler\n",
       "$(&#x27;#mols2grid .m2g-searchbar&#x27;).on(&quot;keyup&quot;, function(e) {\n",
       "    var query = e.target.value;\n",
       "    if (search_type === &quot;Text&quot;) {\n",
       "        smarts_matches = {};\n",
       "        listObj.search(query, [&#x27;data-mols2grid-id&#x27;, &#x27;data-count&#x27;]);\n",
       "    } else {\n",
       "        listObj.search(query, [&quot;data-Scaffold_SMILES&quot;], SmartsSearch);\n",
       "    }\n",
       "});\n",
       "\n",
       "    \n",
       "    // Generate images for the currently displayed molecules.\n",
       "RDKit.prefer_coordgen(true);\n",
       "function draw_mol(smiles, index, template_mol) {\n",
       "    var mol = RDKit.get_mol(smiles, &#x27;{&quot;removeHs&quot;: false }&#x27;);\n",
       "    var svg = &quot;&quot;;\n",
       "    if (mol.is_valid()) {\n",
       "        var highlights = smarts_matches[index];\n",
       "        if (highlights) {\n",
       "            var details = Object.assign({}, draw_opts, highlights);\n",
       "            details = JSON.stringify(details);\n",
       "            mol.generate_aligned_coords(template_mol, true);\n",
       "        } else {\n",
       "            var details = json_draw_opts;\n",
       "        }\n",
       "        svg = mol.get_svg_with_highlights(details);\n",
       "    }\n",
       "    mol.delete();\n",
       "    if (svg == &quot;&quot;) {\n",
       "        return &#x27;&lt;svg width=&quot;250&quot; height=&quot;250&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; version=&quot;1.1&quot; viewBox=&quot;0 0 250 250&quot;&gt;&lt;/svg&gt;&#x27;;\n",
       "    }\n",
       "    return svg;\n",
       "}\n",
       "\n",
       "// Update images when the list is updated.\n",
       "listObj.on(&quot;updated&quot;, function (list) {\n",
       "    var query = $(&#x27;#mols2grid .m2g-searchbar&#x27;).val();\n",
       "    var template_mol;\n",
       "    if (query === &quot;&quot;) {\n",
       "        smarts_matches = {};\n",
       "        template_mol = null;\n",
       "    } else {\n",
       "        template_mol = RDKit.get_qmol(query);\n",
       "        template_mol.set_new_coords(true);\n",
       "    }\n",
       "    $(&#x27;#mols2grid .m2g-cell&#x27;).each(function() {\n",
       "        var $t = $(this);\n",
       "        var smiles = $t.children(&quot;.data-Scaffold_SMILES&quot;).first().text();\n",
       "        var index = parseInt(this.getAttribute(&quot;data-mols2grid-id&quot;));\n",
       "        var svg = draw_mol(smiles, index, template_mol);\n",
       "        $t.children(&quot;.data-img&quot;).html(svg);\n",
       "    });\n",
       "    if (template_mol) {\n",
       "        template_mol.delete();\n",
       "    }\n",
       "});\n",
       "    \n",
       "\n",
       "    // Trigger update to activate tooltips, draw images, setup callbacks...\n",
       "    listObj.update();\n",
       "    \n",
       "    // Set iframe height to fit content.\n",
       "    fitIframe(window.frameElement);\n",
       "});\n",
       "        &lt;/script&gt;\n",
       "\n",
       "\n",
       "\n",
       "\n",
       "    &lt;/body&gt;\n",
       "&lt;/html&gt;\n",
       "\">\n",
       "</iframe>"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 62
  },
  {
   "cell_type": "markdown",
   "id": "d1b35c5d-a39d-43d7-940d-ad7feaffb0ea",
   "metadata": {},
   "source": [
    "Let's take a closer look at the most frequent scaffolds.  We can use the Pandas **query** method to find scaffolds that occur in at least 5 molecules.  "
   ]
  },
  {
   "cell_type": "code",
   "id": "c10fccd2-028e-49d6-9250-656bca4c3c64",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.161454Z",
     "start_time": "2025-05-06T01:16:07.157577Z"
    }
   },
   "source": [
    "uru.value_counts_df(df,\"Scaffold_SMILES\").query(\"count > 5\")"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "                                     Scaffold_SMILES  count\n",
       "0  O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]...     16\n",
       "1    O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1     10\n",
       "2  O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]c...      7"
      ],
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Scaffold_SMILES</th>\n",
       "      <th>count</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>O=C(Cc1cncc2ccccc12)N(Cc1ccccc1)c1ccc(-c2c[nH]...</td>\n",
       "      <td>16</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>O=C(Cc1cccnc1)N(Cc1ccccc1)c1ccc(-c2c[nH]cn2)cc1</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>O=C(Cc1nnc2ccccn12)N(Cc1ccccc1)c1ccc(-c2c[nH]c...</td>\n",
       "      <td>7</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 63
  },
  {
   "cell_type": "markdown",
   "id": "d510ad5d-0cf7-447f-b271-66ee4d772b2e",
   "metadata": {},
   "source": [
    "In the next section, we'll look at how we can plot the activity distribution associated with each of the scaffolds specified above.  We will use the Pandas groupby function to select compounds with the same scaffold.  Once we've grouped by scaffold,  we can compare the corresponding IC50 distributions. "
   ]
  },
  {
   "cell_type": "code",
   "id": "c3a8923b-b43f-4d0d-a9f8-e9a8fb95c588",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.284498Z",
     "start_time": "2025-05-06T01:16:07.196288Z"
    }
   },
   "source": [
    "output_list = []\n",
    "for k,v in df.groupby('Scaffold_SMILES'):\n",
    "    if len(v) > 5:\n",
    "        mol = Chem.MolFromSmiles(k)\n",
    "        mol_image = uru.mol_to_base64_image(mol)\n",
    "        boxplot_image = uru.boxplot_base64_image(v.pIC50.values)\n",
    "        output_list.append([mol_image, len(v),boxplot_image])\n",
    "output_df = pd.DataFrame(output_list,columns=[\"Scaffold\",\"Num Examples\",\"pIC50 Distribution\"])        "
   ],
   "outputs": [],
   "execution_count": 64
  },
  {
   "cell_type": "markdown",
   "id": "c7b60d4d-c1b7-4316-b4b6-7d5fa8ff6154",
   "metadata": {},
   "source": [
    "With the dataframe generated above, we can now visualize the activity distributions associated with the three most common scaffolds. "
   ]
  },
  {
   "cell_type": "code",
   "id": "f434b805-6b5e-4955-9e7a-e944213ab103",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.304250Z",
     "start_time": "2025-05-06T01:16:07.301459Z"
    }
   },
   "source": [
    "HTML(output_df.sort_values(\"Num Examples\",ascending=False).to_html(escape=False))"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ],
      "text/html": [
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Scaffold</th>\n",
       "      <th>Num Examples</th>\n",
       "      <th>pIC50 Distribution</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td><img src='data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAIAAADrOSKFAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO2dd1iTV/vHvw8gQ0LCUgQHCCIRsO5Sq3XWaq3WUff8te5trdu+iAPrrHsriIi496BWrYuK1oKjQLAyRJGprCAzOb8/js3L66okz5OEcD6Xl1eA5HvuoN+c8zzn3PfNEULAYDB0h5GuA2AwqjrMhAyGjmEmZDB0DDMhg6FjmAkZDB3DTPgvKJXKwMDAS5cu6ToQhsHCTPhOCCGnT59u2bLl+PHj+/bt6+/vr+uIGIYJM+FbIIScOnWqRYsWX3/9dVRUlKWlpVwu//HHH1euXKnr0BgGCDPh61y8eNHHx6dXr15RUVF16tRZt27ds2fPQkJCjI2N58yZw+ZDBv8Qxj/8+ivp2/c7+mtxdHRcv359YWEhISQrK+vq1auhoaHGxsYAli5dqutIGQYFMyEhhNy4QTp1IgDx8Tlub2+/fPnygoIC+qO8vLymTZuam5uHhYUxHzKEoKqbUGU/gNjbk+XLlXK5vPwTlErllClTAJiamp4+fTowMNDIyMjExHzLlqe6iplhYBisCVNTSWLiq8d37pCSEhIRQfLzCSEkK4skJZGICNKjxyv7WVmROXNITs7bpVQ+NDMzoz789NPHAFm5UjtvhWHgGKwJDx8m69a9ety7N8nMJK1akWnTCCHk3DkyezbhOAIQiYQsXPhO+6l4zYehocTYmADE31/Yd8GoClShu6MSCfLzcecOANjZYfhwLFiAhAT4+UEi+ZfXchy3fv36SZMmFRcX+/qetrUlu3bByAgLFmDZMi3EzjBkTHQdgIDs2/fKcn/++eo7y5Zh6FB8/z0ABAVVTI3juI0bN4rFTbdsGdW7N3fiBHbvxqhRWLAAAObP5zFwRtXCkGfCYcMQHIzgYLRo8eo7Dg7o3RuBgWoKchzn7z96+HCusBBff40aNbB7N5sPGZpiyCZ8KxMmIDFR/ZdzHDZswOTJKC7GN9+gRg3QdemTJ7hy5dVzEhKQnc1HrIyqAUcMtLzF06coLIS7OwCEh6NVK0REoF07APjjD4jF8PBQX5wQTJ2KTZtgZoajR2FtjRYtIBZj/3706wc/P3TsiPbt+XkjDIPHYK8J69T57+M2bQCgXTsUFKB2bZSWIj9fI3E6HyoU2LoVFy9i7VoUF6NDB2zdiq5dNVJmVEEM1oRvxdIS1asjNRVPnsDZWSMpjsPmzWjXDgMHvvqOqSmmTIGv77/fa2UwylPlrgmlUgCIjeVBiuMwaBA47r/f6doVaWn8iDOqDlXOhI0aAYBMJpT+qlU4f14ocYZBUuVMSGdC3k3411+YMAEA6tTByZNo2JBnfYYBU7WuCcHrclTFixfo1Ak1a+LTT2Fjg44d+RRnGDxsJuSB1auRl4cGDWBjw6cso4pgsPuE74IQSCQoKEBGhsLOzlhzwawsuLoiPx8REfDx0VyPUeWocjMhx6FDh5mmprYyWQQvgitWID8fPXsyBzLUpMqZEIBEkl5UlC3jY0maloYtW8Bx+M9/NBdjVFGqogmlUikAXky4fDlevkSfPmjVSnMxRhWlKpqwUaNG4MOEz57lBAUVGhnBz4+HqBhVlqpoQjoTxv6zTXHq1Klbt27l5uZWVMfff4GZmdv06WGNG/McIaNKUeXujgIoLS21tLRUKBQFBQVmZmZisVgulwOwsbHx9PT08vJydXWlD+rXr8+VP5ZWjuTk5IYNG5aVlT148IBOrQyGelS5zXoA1apVc3V1jYuL+/vvv11dXXv27CmTyeLi4rKzs8PDw8PDw1XPFIvFUqm0UaNGUqlUKpV6enq6urqamJgAWLJkSXFx8fDhw5kDGRpSFWdCAN27dz9//rybm9ugQYM8PT09PDykUmlubm5MTExCQkJ0dDR9kJCQ8NoL/f3958+fn5SU5OHhoVAooqOjPTRJTGQwquZMCKBjx45hYWHx8fHly9qrlqOenp49e/Z0dXUVi8WxsbEymUwmk8XExMhkMk9PTwB+fn4lJSXfffcdcyBDc6roTAjgzJkzKSkpT58+jYuLi42NffjwYUlJyWvPsbW1bdSoEV2O0r9dXFzi4+M9PT05jpPJZK6urjoJnmFIVF0TvkZZWVliYmL5eS8uLi4nJ+e1p5mbm1evXv3Fixfjxo3btm2bTkJlGBjMhO8jOztbdX1IHyQmJgKwtLTcuHHj//3f/+k6QIYhwExYMfLy8pYsWbJ69ermzZvfuXPnXRsYDMaHw0xYYYqKitzd3Z8+fXrs2LE+ffroOhxGpacqnpjREHNz87lz5wLw9fVVKpW6DodR6WEzoTqUlJR4eHgkJSUdOnSof//+ug5HT8nPz/f19ZVIJFKp1MrKysrKSiQSWVtbi8VikUhkbm6u6wD1BWZCNdmxY8e4ceM8PT0fPHhgZMQWFK+jVCpr1qz5/Pnzdz2hWrVqIpHIxsZG5U8rKysbGxv64PHjx19++eWAAQO0GbOuYCZUk9LSUqlUmpCQEBISMmTIEF2Ho3ds2LBh2rRp1apV69q1a/Xq1fPz8+VyeX5+fl5eXk5Ojlwuf3NX9k3mz59f/jSFocJMqD4BAQGjRo1yd3ePiYmhB0oZlMePH3t7e8vl8mPHjvXu3Xv//v10fpNIJGKxmM571apVk8vlubm5ubm51J/5+fm5ubl5eXn5+fl79+5NSkqSSqXR0dEGv9BgJlQfhULh5eUVFxcXFBQ0YsQIXYejR3Tt2vXChQuDBg0KDQ0tKCgQiURvPofjOGtr67euRQcPHtyiRQsPD4/ExMQDBw4MVBU5N1R00ZnUcNi7dy8ANze3kpISXceiL+zevRuAnZ1dWloaISQvL2/IkCE9e/bs2LFjixYt3NzcHBwcqlev/p7/k0FBQYSQHTt2AKD5Yrp+T8LCZkKNUCgUjRs3jo2N3bVr16hRo3Qdju5JS0vz9PTMzs7et2/f0KFD3/NMhUKRl5eXm5urulxUrUW7desmlUpVV93/KlXp0fWnQKUnNDQUgLOzc3Fxsa5j0T19+/YF0L17d17UAgMDAbi7u5eWlvIiqJ8wE2qKQqH46KOPAGzdulXXseiYgwcPAhCLxcnJybwIlpWV0WSxwMBAXgT1E2ZCHjh8+DAAJyenly9f6joWnfH8+XMHBwfeP4yCg4MBuLi4GPBCg5mQB5RKZdOmTQFs3LhR17HojOHDhwNo3769UqnkUbasrIwWENm5cyePsnoFMyE/nDhxAoCjo2NBQYGuY9EB586dA2BhYfHw4UPexQ8cOACgXr16RUVFvIvrA8yEvPHxxx8D+Pnnn3UdiLaRy+X169cHsGrVKiH0lUplkyZNAGzZskUIfZ3Dtih44+zZsz169LCwsCCE2PyDhYWFubn5v35pb29vamqq63egJpMmTdqyZUuzZs1u374t0Mmho0eP9uvXz8nJ6dGjRxYWFkIMoUt0/SlgOGzevBmA2l7iOK5fv366fhMV5vfffzcyMjIxMYmMjBRuFKVS2bJlSwAbNmwQbhRdwWZCfkhOTvb29s7Pzz969OiXX36Z/Q9FRUWFhYX/+mVWVlZpaSmAwMDASlQ1o7i4uFmzZrGxsb6+vosWLRJ0rFOnTvXq1atWrVrx8fHvP3BT6WAm5Icvv/wyLCysX79+hw8fPnfu3JQpU147Fal6bGVlVf7MpFgstra2tra2/uGHH9atW1e5qmbMmjVr9erVUqk0KipKC/mBPj4+t2/fXrNmzYwZM4QeS6voeio2BPbs2QPA2to6JSWFEBIUFFTRf4WUlJTCwsI6deoAOH78uK7f0Adx9epVjuOMjIxu3rxJCOF3Z+KtnD17FoC9vX1+fr7QY2kTNhNqSlZWlqenZ2Zm5p49e0aOHAmgsLAwNTX1raci6XdycnLol/SnOTk5ycnJIpFo8+bNkydP9vb2vnfvnv7n79BMLnNz85cvXx45cmThwoVHjhyhxZGF47PPPrtx48aKFStmz54t6EBaRdefApWefv36AejcubPmU0FxcbGLiwuAQ4cO8RKboGRnZ9va2gI4duzYpEmTAAwYMECgsXJychITEwkhv/zyCwATE5PMzEyBxtI+zIQacerUKQCWlpbx8fG8CNKCwp6engqFghdBQaE3hL28vJ4+fWphYcFx3N27d4UYaOzYsSKR6MiRI8nJyfSCma9fuD7ATKg+OTk5tWvXBrBp0ya+NEtKSmhp/f379/OlKRwlJSV0m/7gwYPTp08H0LdvX95H+e233ziOMzU1/euvv3r37g2gUaNGvI+iQ5gJ1efbb78F0Lp1a35nLZoUW1nyd7Zv306n7pSUlOrVq3Mcd/v2bR71CwoKGjRoAGDJkiX79+8HIBaLnzx5wuMQOoeZUE0uXbrEcZyZmVl0dDS/yqr8HZpgrueopu6QkJBZs2YB6NmzJ4/6dDfio48+Sk1NrVmzJoAdO3bwqK8PMBOqQ0FBgZubG4CffvpJCH26yeHm5lYpJsOAgAA6daemplpZWQGIiIjgRfnWrVvGxsbGxsZ//PEHLWnXoUMHLeyFaBlmQnWYOnUqgCZNmghUWkaVv7N7924h9PlFNXXv2bNn3rx5ALp166a5bHFxsbe3N4DZs2fTHcLq1av//fffmivrG8yEFebmzZvGxsYmJiZ37twRbhR6/VNZqmbQglcuLi7p6enW1tYArl27pqHmwoUL6QSblpZWt25dGG6GCjNhxSgqKqL70QsWLBB0IFXVjG3btgk6EC+opu5du3b5+voC+PzzzzURvH//vqmpqZGR0dWrV8eNGwfg448/NtSya8yEFWP+/PkAPDw8CgsLhR7r0KFDAOrWrVspkllpwat69eplZGTQTfzffvtNPSmFQtG6dWsAEydOvHLlCt2fePDgAa/x6hHMhBXg0KFDxsbGRkZG169f18JwqqoZPO5DCkf5gleLFy8G0KZNG/WkVq1aBaB27dqpqanu7u4AFi1axG+0egUzYQWg3QibNGlCCMnMzNTC4bLjx48DcHR0rBQlpFQFrzIyMmrUqAHg4sWLFRVJSEiwtLQEcPLkyZkzZwJo3LhxpbgwVhtmwgpAj2vQvEFbW1sTExMhSqq8RqtWrejCTOiBNKd8watly5YB+PTTTyuq8PnnnwMYPnx4ZGSkiYmJkZHR77//LlDAegIzYQV4+fKlk5MTgDNnzowZM4b+XxForDlz5mzZskWpVNJkWQcHB4EG4hdVwav09PSaNWuKRKJHjx59+Mvp0Vl7e/tnz541a9YMwKxZs4SLVk9gJqwYP//8M4DmzZsnJSWZmZkZGxvHxMTwPsq1a9eMjIyqVasmk8m++uorAK6urryPIhCqgldXr16taK4D7atz4MABPz8/APXr15fL5QLFqT8wE1YMVertiRMnJk6cCGDQoEH8DlFUVERv9y9cuJDeIBWLxZVok/rMmTMAatSooV7q7dWrV2NjY83NzTmO+/XXX3kPTw9hSb0VZtOmTVOmTPH29g4LC3N3dy8uLo6KiqI3Bnlhzpw5K1eulEqlly9fbtasWXp6+tatW8ePH8+Xvhbw8vJKTEwsLCw0Nzf/wHpzqscSiWTAgAE3b94cP3781q1bdf1WtIKuPwUqH6rU28OHD9Pza9988w1f4lFRUdWqVTMyMgoPD6drM95rWgtNVlaWnZ1dtWrV1P4/aW5u7uDgkJOTo+u3oiXYTKgO27ZtmzBhgpeX14ULF9zd3QsLCyMjI+mNQU0oKyvz8fGJjIycMWNG9+7du3TpYmpqGhUVRVenlYVhw4aFhIR06NDh8uXLqooetIpH+S+zs7NVj8v/NDc3t7S0tH79+rGxsZWl4JWm6PpToFKiyt8JDQ394YcfAPTq1UtzWbrHTU9g0mTZlStXai6rTWg9fE1OWle6gleaw0yoJrt27cL/5u/cunVLE0HV3YgLFy7Qki1NmzatXA2Ac3Nz6UnrNWvWaKKzadMmAN7e3pWixofmMBOqSVlZWcOGDQHs3bt37ty50KwzpkKhaNOmDYCxY8dqp6a1ENC7R5qftK5cBa80h5lQfWi50QYNGqSlpYnFYgBqnyldu3YtAEdHx9TUVHoF6Ovry2+0QsPvSWtV1YyqMBkyE6pPWVmZVCoFEBAQ8OOPPwLo0qWLGjqJiYkikYheBc2ZMweAVCrVQpYGjxQVFdFfhZ+fHy+C5atm8CKozzATakRISAgAZ2fnjIwMGxsbAFeuXKmQglKp/OKLLwAMHjz47t27dH/ixo0bAgUsELS6TKNGjXjMuqpcBa80gZlQIxQKRePGjQFs376dnrRq27ZthRR27twJwM7OLiUlpXnz5gC+//57gaIViMjISNXeJo+ylavglSYwE2rKwYMH8U8ya+vWrfft2/fhr83MzKTFIEJCQpYuXUr3JypXo4XS0lJ60nrmzJm8i9OqGW5ubpXrLnFFYSbUFFUf2c2bN6vx8v37948cOVImk6n2J3iPUFBokodAJ63LV83gXVx/YCdmeOD48eN9+/Y1MTEZOXKku7u7tbU17YImEokkEolEIqFf0lzVN1Eqle3bt79x48bo0aPp6rSyIJPJmjVrVlxcfOHCBZoHyDuhoaFDhgxxdnZ++PBh5W1m/H6YCXlAqVTWrFnz+fPn738ax3HW1tZisVhlUdq3MD4+/urVq05OTtHR0XR1WilQKpXt2rULDw8fN24czQMUaJRmzZrdv39/27ZttOKT4cFMyA+5ubnTp0+vUaMGx3GvHZJUfVlYWPiul9va2k6dOpUW+assrF27dsaMGVr47Dhy5Ej//v0NtmE9M6E2USgUeXl5b/YtPHny5OnTp1u2bHn79m1tHlm+du1aUFDQF198oeoiLJFIxGKxlZWVmZnZ+1+blJTUuHFjuVx+4sSJXr16CRonIaR58+Z3797duHHj5MmTBR1LJzAT6h5aVD89Pf3s2bPdu3fXzqA//fQTLd/4VkxNTUUi0VsXz/TiNiQk5O7du0OGDKE7pUJz8uTJ3r17Ozo6Pnr0yMAa1gMsi0I/oFUzWrRooZ3Uwby8PHrSulatWv379+/WrVvbtm2bNGni6upqa2v7IamATk5OlpaWGRkZZWVle/fu1ULiv6pqhtADaR82E+oFRUVFDRo0SElJ0cLqDsDEiRO3bt3aqlUrWtL/zScUFxfn5+fn5eXl5OTQlbNcLs/Nzc3NzZXL5dnZ2UFBQXl5eWfOnPn999+XLVs2bNiw4OBgQWM+e/Zsjx49rKysHj16RNszGQ66/hRgvGLDhg0AGjduLPSRZXrSWsMsDe0UvCKE3Lt37+OPP6ah0rsylaJJToVgJtQXVPk7R44cEW6U8lWkNNHRQsErQkhZWVnLli0BTJ48WdWv9+bNm7wPpFuYCfWIbdu2NW/++Vdf3RFuLuTxpPXGjRsBeHt704b1RkZG9+7d4yVIFStWrABQr1699PR02q938eLF/A6hDzAT6hHFxUoXFwKQ0FBB9MtXkdJcTdCCV4SQhw8f0vXn+fPnVf16DbIePjOhfrFzJwFIw4aE9/Qd1UnrH374gS9NWpLQy8tL1bA+KiqKF2WlUtm5c2cAI0eOLN+vlxdxfYOZUL8oKyMNGxKABAfzrEyrSNWvX5/HLA2BCl4RQrZv3wnAwcHh2bNnqn69vCjrIcyEeseePQQgDRrwORkKV9Oa94JXhJAnT0i9ei/atBl5+PBhf/81VL9S9KVSD2ZCvaOsjEilBCABAfwIlq8ixY9iOcoXvKK1OTQpeEX5+msCkJ49yYMHRCx+2aHDzIrWK6hcMBPqI/v2EYA4OxNebkPQPT1HR8fs7Gwe5N6Ax4JXhJDgYAIQiYQkJ5PWrQlAJkzgMVh9pAqdmAkMDJw7d65cLndyclKdVKanIt91SJJ+hxaP0SZKJZo0QaNG2LIF9vYaSalOWh8/fpz2V+QdhULh7e0tk8kCAgISEhKWLl3apUuXCxcuqCGVlQUvL2RkIDAQWVmYNQtOToiORuVJ8FILXX8KaAna1lPt35KpqamDg0NYWJjWAi4oIJMmkefPCSHkwgVy/746IuWrSPEb3muoCl6lp6erV/CKMnAgAUinTiQ+nlhaEoCcPMl7sHpHVZkJp06dunHjxoYNG548edLIyEiV5kcPRr7rkKSqOwIVcXZ2TkpK0lrM9euja1ds24bVqyGVokePCivs2rVrzJgxdnZ2MTExgp63pD16Hzx4sH379tTUVD8/v7Zt216/fr1CItevo107iES4fx9jx+LiRQwfjr17BQpZj6gSJoyIiGjbti3HcfTGXYsWLSqqEB0d3bZt25ycnF9//VWgOg5v8sUXcHXF8OG4eRMeHjh6FCIRrKxgbQ0rq1d/RCLY22dWr55NV870/iQlOTm5SZMmOTk5QUFBtMGToBw6dGjgwIH16tW7c+eOVCp98eLF5cuXO3bs+OEKhCAgAIRAocD48bC3R0wMatQQLmS9QcczsfAUFRV5enoCWLBgAW3mPG7cuAop5OTkRERELF++HEDr1q0FivNNunQhmZmkY0eyfDk5cIAAb//TocOV8v+g1tbWdevW9fDwUCWhr1u3TgvRli94tXbt2nnz5j2ni+mKM2IEAciBA/wGqL8Yvglp6qqHh0daWlrt2rUBbNiw4cNf/ujRI1tbW0dHx8zMTAcHBwDnzp0TLtry0HLeO3YQqZQcPUoCA8mGDcTfn8yZQ8aPJ0OHkq+/Jp06kaFDwxo0aFCrVq03C0nRBPlatWoVFBRoIeBjx44BcHR0VGNP79YtcufOq8enT5OrV3mOTZ8xcBOqalpfv379u+++A/DJJ59UtF0JTSdds2bN6tWrocXUW2pChYK0bk1On/6glyiVyhcvXvz222/GxsYmJib379/38fEBsGrVKkFDVY3u5eUFoH79+tOnT//Pf/6zYsWK7du3h4aGnjlz5sqVK1FROfHxJCODvFnjf9484uVF6GGejh21EKweYcgmLC0tpZd/06ZNu3z5MsdxZmZm0dHRFdU5e/YsAHt7+4yMDDqXnjp1SoiAVfz5J5k4keTmqq8wcuRIAKNGjTp//jwNPi8vj78A38nSpUvfUyanVas01SraxITY2BBXV/LRR2TgQDJvHvH3J/RYKzOh4bBs2TL8c9/czc0NwLJly9ST+uyzzwAsX758/fr1AJo1aybcZFhSQpo2JQDRpC9TYmKiqampsbGxTCajwf/000/8xfg+fvnllw0bNqxZs2bRokUzZ84cO3bsgAEDunfv/tlnn/XunenqSuzsiJnZ/1zWNm9O5s0jt2+TgQPJvXvMhIZCXFwcvTMRFhY2bdo0AE2aNFG7mjrderazs8vMzKTJrEePHuU3YBVLlhCAuLgQDQ9ajxo1CsCIESMuXrxIg8/VZG7lm+Ji8vw5iY8nUVHk/v1XJkxOJj17MhMaBAqFgn78f/fddxEREfQC6Y7qwl8t2rdvD2Dp0qWbN28G4OXlJUQdCpmMmJsTjiOal8N//PgxnQxjY2Np8CvVXQhoAWpCQsiKFcyEBgFN+q5Vq1Zqaiq9VTB//nwNNenWs7W1taqh/MGDB3mJVoVCQdq2JQAZM4YfQdo6d/DgweHXrq1r376wVi0izPFRzXn6lNBmFiUlJC5O19FoFwM04ePHj+me9dGjR2nvzoYNG/LSc7NTp04AFi5cuGPHDiqrYV/o11i7lgDE0ZG8eMGP4JMnT+o4Oa3p2JH89Rfp3FnTC02GMBigCbt16wagf//+9+7do/sT165d40U5PDwcgEQiSUtLo8msFWqE9n4SE5+LxWW8n5YsmzaNAKRfPxIeTgAiFhN199AZAmFoJgwMDARga2v79OlTWqhrypQpPOrT89ALFiwICAgAf31klUplly5dvLx8Jkx4pLna//DsGalenXAcuXuXdOtGAKLxypzBLwZlwtTUVJoqERQURE+ZOTs787s/9scff3AcJxKJnj17RvvI7tmzR3NZmp9uZ2eXnp6uudrrfP89AUifPuTOHcJxxNKSCDEKQ10MyoS0kFHnzp1lMplqf4L3Ub766isAc+bMoTWnXVxcNCwB9uzZM5r+ExISwleQ/0NGBhGJCMeR27dJjx4EILNmCTIQQy0Mx4QJCQkAOI6Lj4/fv3+/ubn5yJEjhRjozz//5DjO0tIyJSWFFtLduXOnJoJ9+vQBH1Uh3sfs2QQgPXqQyEjCccTCgqSkCDgcoyIYjgkzMjJoW4XLly8TQmQymdqn+P8VmqI+Y8aM0NBQAHXq1ImLi3vx4oUaN0tpy3uxWJycnCxEqK/IyiJWVgQgERGkTx/i5UU0qIHP4BeDyidcvHjxwoUL27Rpc+PGDUEHunfvXu/evRctWjRs2LC6deuWlJRkZWXRH1lYWJSvkaFK87OxsVGVzxCLxbSldkZGxpgxYzIzM7XRhnbBAixbhtGjsXIlJBIYGQk7HOODMSgTyuVyV1fXzMzMixcv0tKxwqFQKIyNjSMjI318fDiOc3BwKCgoyM3NVSqVFdIxNTVt3bo1bbQgUKivePECZ89iyBDs24fz58FxaN0aU6cKOyjjAzAoEwJYvnz5vHnzPv30U7qnJyhlZWU+Pj6RkZEzZsxYs2YN/WZBQcGbNTLkcnlOTk5eXt5rPbQfPnxYr169bdu2ffLJJ0JH+4rbt7F2LUJCYGSECRPQsye01ZaU8U50vBzmG7lcToupnD9/XuixlixZAsDFxYXHmtaC4+//39MA4eHk++91Gg2DEEIM7cLA0tKSNh768ccfiZCTfFxcnL+/P8dxO3bsEIlEwg3EP6pfCyEQeg3M+AAMzYQAJk+e7OTk9Oeff9JkXCFQKpWjR48uKioaPXp0ly5dBBpFEDp3xuHDr3x44AAEvnJmfAgGaEJzc/PZs2fjnz6YQgyxcePGGzduODo60gZ6lQkfH7Rvj8GDMXgwXFzYBaE+YGg3ZihFRUXu7u5Pnz49duwY3QrnkcePH3t7ewta05pRpTDAmRCAubn53LlzAfj6+lZ0z+D9EELGjh0rlz277UwAAAH4SURBVMsHDRrEHMjgBcOcCQGUlJR4eHgkJSUdOnSof//+fMnu3r179OjRWqhpzag6GOZMCMDU1HTevHkA/Pz8+JoM09LS6K3X9evXMwcy+MJgTQjg22+/dXV1jYmJOXDgAC+CkyZNys7O7t69+9ChQ3kRZDBgwMtRSkBAwKhRo9zd3WNiYkxMTOLj4y9duvTWY5ympqbvl6K9FsRi8V9//VW3bl3txM+oChi4CRUKhZeXV1xcHG2KsnfvXloV903MzMxEIpFEIpFIJKpT1xKJZPXq1VZWVs+fP/fy8kpPT9fGSWtGFcPATQggODh4xIgRbm5usbGxERERwcHB9BinqvMZPcZZVlb21pfn5+eLRKIRI0YEBwe3b99eGyetGVUMwzehQqHw9PR8+PChu7v7qFGj3roWtbKy4jiO2jI7O1t16jovL2/MmDFhYWHdu3e3sLC4d++eu7u7rt8Qw9AwfBMCmDFjxtq1a9//HGNjY7FYLJFIVEmAtKW2XC4/ceJEcXHxypUr6a1RBoNfqoQJAezcufPSpUvOzs5vTSnKz88vKip6z8slEklWVpaJiYnWAmZUHaqKCf+VsrIyuhZV+ZNaNDY2tri4ePHixXZ2drqOkWGYMBMyGDrGkDfrGYxKATMhg6FjmAkZDB3DTMhg6BhmQgZDx/w/tbb27M1gzFkAAAJIelRYdHJka2l0UEtMIHJka2l0IDIwMjQuMDkuNgAAeJx7v2/tPQYgEABiJgYIUABiFSBuYORg0ADSzExsEJqFjSEBpI6JzQHKd8gA0cyM7BABZrgAhgq8DIhadgaoIbhsIcUwfDIYjrcAMRiZ8XkHyuBmYNRgYmRiYGIGmpDBxMKawMqWwcTGnsDOkcHEwZnAyZXBxMWdwM2TwcTIq8DLx8DHz8AvkMEkIJggKJTBJCScICySwcQrqiAqlsEkJp4gLpHBJCGpICmVwSQlnSAtkyAjCxSQS5CTz2DiYU4Q4U+QF03gYU+QlUxwYgU6gY2FlY2dh5mNg5OLm4edTUBQSFiEn01MXEJOXpRVSlJWRlq8i5GBgZEBFpdc0i/tF/dHHgBxolkn2X9mYAGzRVb/sl8o4LcfxLYzjnUwiUgCs7njWxz2qvCB1Tz13eKwyEwYzA4uP+ewrrgVrObFxh0Ox5dNswOxw25fcnBffMwexH4lutch+IGFAzhBqfc6WHyyBbOdf6c63H51C6yG93CHwzvT/WC9Zje27ZO59xds5vHoaftvZvuD7ZrBrX3gS6QXmJ0/LexAx7SXYDVCVrMP7Cu6D2Y3JG89oGXmAPHLvPkHch91gdklcfEH4rN7wey9p1v2VzaqgtUrGCTu21QoA3ZDennafouwn2B2X7XkAca9jGB3prG5HtjoHQ5m/3818cCJ6DQwuyZ95oHW6YvAbA+H2AMfY3aA2VvSJA88SJ8GZmef8z1wk8EVbOZkZ6UDTy0FwfaKAQBW4qZTvyyu2QAAAu16VFh0TU9MIHJka2l0IDIwMjQuMDkuNgAAeJx9Vltu2zAQ/PcpeAEL+yS5n00cFEURG2jT3qH/vT86SyWUAhCVwoUtj5azs8NFLiWvH7fvf/6WecntcimF/vMXEeW3EtHlteSH8vTy9du9PL99efp48vz4dX/7WVSKVryD+zP2y9vj9eMJl0fhrQuz9nLVTSM0pNBG4zpelfIMIBu1DqBsVMW9L4A6gOFdrZYrbZ0sjBdAA1A3cyTSAezGy4wOoG2stZLk1iJQYcWxlnvxrao5RQIhE6ALYEPGiq2FKjjyRiYeugB2AH1rjXHjZwmTZS0xEnoPaYbq3bkvS2EaCYOA9CKouddlKcyjaGMm7gBGbbEshWXICPpWGVs3Jlln1JFRmnawoE0bdFpyNMiIfqg3xt6QJ7rqsmzO1gDAzWqr6R8xCm8raE2obLUJrJFQrniNVtBsT3rRJWDia/rTguoKmg262tadukZCGwzVl0Jlj66wRwVycCVSXWYV2rNGh3lbflIjXnIV3rmCXwKu2bLQpQIiu1ikUKunwtWq0xKavQJAOGI0qzKu5f62IwNW98iDZy3MVkjfG6DRGa7HCZaGFqyQda8JR93RYTSiYiz4Ctl2odwxNuqwIYpfjo+eprKthfYuOALUcYiX4se7ot7Iep6+ynDqatJQ5syK0HGFtxvhsKxU0vcuCXuTFKfV8KVKKrtKro42pbIOx8Yq6cv99mmU7sP16XG/HcNVch0jNB/oMSgZy45xmLcfQw9fSj1Gm2G1Y4AZVj/GlGHFMY0Mi89TxzIwn8aLZeBJDnPEMvDkx7oXMBliMPAIkyTcwSNMnpxEEXhS5eSKwJMtJ10EnoQ5GSPI+QhaBpmUcdLG7nLomZQRZFLGubEMMjlLioogk7Mk5xy+k7MkZwSZnCU5I8jkLMkZQSZnSc4IevZjbgS3nXxnGXRy1iHzqe06KPNJQk3KwB2Fqu8vTTaajAfzsxnP1svvH/8T4PPlH19wjsiu55enAAABd3pUWHRTTUlMRVMgcmRraXQgMjAyNC4wOS42AAB4nCVROa5cMQy7SsoZwM/QvmCQ6jepkgMEqV4/J/iHD+VxZdOUSFF/fn49vm6+3/ct9xyW5++DnMfzXB4XPv++f/273/IE+uP7wbuE2dalW7u114s3G2WvSzaFeAzSXurrol1kbbxeus3xeaAy9lov26wRUyZCjUa+Q815ECUSVAWqhHJdvMnEDyeTUxZtaRM7HK+WXLzduWIoTdW6BEoVPULGTAKgI/uY8VYLlCTww5DUYnTVhAWYg0/1ZK7R7lI1YJg0LWpmF6OGFqxGih+IA7+AEIwL9K+Jykbvsl1OZQMlcoDihWGjToxEqh9SVxEisq1G/GllPbdrRmiN44E0LSfIsHCEM16Fu8d+MM5BGgkiMJi3bDtOtYsTKZAkx+lOWS4LhkNnAZBxb7AnoMYCB8nWquWbij+OPGESewg+jOkb1QtMIq7DEfazo4x2+4i7uh7XjsB6Pb//AypIhOZ/c9qnAAAAAElFTkSuQmCC'/></td>\n",
       "      <td>16</td>\n",
       "      <td><img align=\"left\" src=\"\"></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td><img src='data:image/png;base64, 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'/></td>\n",
       "      <td>10</td>\n",
       "      <td><img align=\"left\" src=\"\"></td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td><img src='data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAIAAADrOSKFAAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nO2daVxT19bGnwAym4AiAorIJIjihKK2DqioWMXW63hr1fbWiVq9VWuxKg61KmqtVqsWLL0oahW8rYivVgFxxglRKwgO4FAFEoYQpjAk+/2waUqt9kJyDoFk/3/9cDgma6+kec7a41oCQggYDIb2MNC2AwyGvsNEyGBoGSZCBkPLMBEyGFqGiZDB0DJMhK+lrKxs586dd+7c0bYjDB3HSNsONEXKy8v37NmzcePGkpISAwODn3/+eejQodp2iqGzCNg6YV0qKirCwsJCQ0Pz8vIAWFtbFxUVWVhYHD9+3M/PT9veMXQT1h2tpaqqKjw83M3NbeHChXl5ef369Tt27FhBQUFQUFBZWdno0aOTkpK07SNDRyF6j1xOdu2qcnFxpV9Inz59/u///o/+040bNx4/fjx37lwA5ubmZ86c0a6rDJ1Er0VYVUX27iUuLgQggwcv8Pb2jo6OViqV9F9TU1OtrKxcXFyePHkyZ84cqsOkpCStuszQQfRUhFVVJCyMODkRgACkRw9y7FiFSn4UqVTat29fAE5OTo8ePZoxYwYAZ+d+ly7VaMtthk6igyK8fp0UF9deJyQQuZzExtb+eesWEYvJ3r3Eza1Wfl26kL17iULxalMqHXbs2PHRo0dBQStcXOQtW5JLlxrjgzD0BB0U4axZJC2t9nrAACIWEzMzEhNDCCELF5IVK2rl17UriYl5rfxUSKVSX19fAG5ubk+e/DZtGgGIhQU5d47fT8HQH/RidnT0aOzeDZkMAAIDMWwYDh3C7duYMAEG/+sLEIlEv/zyi4+Pz8OHDxcuvLZuHaZNQ1kZAgNx5Uoj+M7QfXRzsX7pUohEAFBZCQDGxggOxsqVMDCAsTESEhpmzdraOj4+/uOPL/74Y2BaGuLjQQj270dAAE6dQt++3PvP0Ct0U4ShofDyAoCBA2vvjBiByEgUFqpp0NraeufOwPv3ceMG/P2RkABCcOAARo5kOmRoil50RymbNuHSJfXfbmWF+Hj07o379+Hvj/XrMWkSysqQlobs7NrX3L/PiacM/UIHt63dvYuOHWFpCQBXrqBXL9y/j65dUVaGq1fRpw9atlTfuFQKf3+kpMDDA/HxePwYBQWYPRt378LWFkOGgO2rYTQUHYyEXbvWKhBAv34wNkbXroiNhaUlduzQSIEArKzwyy/o3h2PHuH27dru7ttvIzhYU7cZeosOivCVdOwIABkZHJiysUF8PI4dw5gxtXd69ICZGYuBDDXRwe7oK5HLYWkJAwOUlaFFCy4tHz2K58/x7ruYMAHV1Th/nkvjDH1AXyKhqSk6dEB1NbKyeLFvbY3p05Gayotxhm6jm0sUr8TTE9nZyMiAhweXZs3NQU8aTp8OQ0MuLTP0BH2JhECt9jgZFqo4fhwBAfj2WwAQCPDee1waZ+gJeifCzEzODBKClStBCDw9ObPJ0EP0SISdOwPAkycKrgz+979ITYWDA2bP5sokQx/RIxF6eEhtbLrcumXLiTWlEmvXAkBICMzMODHJ0FP0SIR2dlY1NS8KCwslEonm1n78EXfuwMkJ//qX5sYYeo0eiRCAh4cHgAyNJ2cUitowuGoVjI0194uh1+iXCD09PcGFCA8dEmdmwt0d06Zx4RZDv9EvEdJImJmZCaCgoODAgQMpKSllZWUNMlJVVbViRd8ePYauWyc20qN1VgZf6NePqK4Ir1+//t7v63r29vZdunRxcXHx8vLq0qWLt7d327ZtX2ckIiLi8ePHXbpYjB9v0zhuM3Qb/RJh3e6oSCSaOHFienr6gwcPcnJycnJy6r7Szs7Oy8vL09OzS5cunp6eXl5ednZ2AORy+fr16wGsWbPG4H/mxmAw6oG+bOCmVFVVmZubKxSKgICAfv36UZm5urrm5uZmZWWlpaWlp6enpaXdvn27tLT0pfdmZmZ26tRp27ZtCxcu9Pb2vnXrFhMhgxP0S4QARo8efeLEibp3jIyMOnTooOqLenl5devWrbCwMCMjIy0tLSMjIz09/dGjR7/99ltlZaWrq2teXl5cXNwY1UEmBkMz9E6EVVVVNM12eno6FVhWVpZC8adtNAKBoEOHDnX7op07d27VqtXGjRuXLl3au3fva9euCQQCbX0Eho6hdyL8K5WVlZmZmVSQ9+7du3fvXmZmZlVV1Usvs7W1lclkcrn81KlTI0aM0IqrDJ2EifAV1NTUPH36tO4o8c6dOyUlJQ4ODqWlpTk5Oebm5tr2kaE7MBHWC0LI06dPx48fn5KSsnnz5k8//VTbHjF0BybCBnD69OmRI0fa2NhkZWW11DBjFIPxO2ySvQGMGDFi4MCB+fn5u3bt0rYvDN2BRcKGkZCQMHz48NatW2dnZ7NgyOAEFgkbhr+//+DBgwsKCr6lOS0YDI1hkbDBXLx4ceDAga1bt87KyhIKhdp2h9HsYZGwwQwYMMDPz6+goGD79u3a9oWhC7BIqA6XLl0aMGCAlZVVVlaWtbW1tt1plmzfvv3SpUsjR4784IMP9H37kVZKk+oAw4YNA7B69WptO9L8UCqV69atU/0CHR0dg4ODHz9+rG2/tAaLhGpy+fLlN998UyQSZWdns2BYf6RS6bvvvnvy5EkjIyNHR8eamppnz54BMDQ0HDVq1MyZM996660W3BYqaPpo+ynQjKE7SFeuXKltR5oNGRkZ9EinjY1NYmIiIUShUMTHx0+cONH491w9dnZ2CxYsuHPnjradbTyYCNUnOTkZgFAoLCgo0LYvzYC4uDiRSASgR48eWVlZoaGh8+fPV/1rYWFhWFhY9+7dVeHBx8cnLCyspKREiz43DkyEGhEQEABg+fLl2nakSaNUKkNDQ+kZ6H/+85+5ubljx44FYGRkdPfu3ZdefOPGjdmzZ6s2QgiFwmnTpsXHx2vF88aBiVAjbty4IRAILC0txWKxtn1poshksnHjxgEwNDQMDQ29f/++l5cXgFatWp0+ffp17yovL4+Ojvb391dNnHbu3Dk0NFQnv2cmQk0ZPXo0gKVLl2rbkaaISnKtW7eOj48/ceKElZUVgG7duj169Kg+FtLS0hYtWtSmTRsqRRMTE3d397/Gz2YNE6GmpKSkCAQCCwuLvLw8bfvStHhJcqoe6aRJk0pLSxtkqqamhs7fGBoaAnB2dubJZ63Alig4YPjw4WfOnBEKhW3bthUKhSKRSCQSCYVCoVDYsmVLesfKyope172jq4vUhJBNmzYtW7ZMqVROnjx5+/bt8+bNO3LkiEAgWLly5apVq9T+4PQ0mYmJSUVFhe58e9p+CjR7FApFr169TExM1PjyLS0tra2t7ezs4uLitP05OKOkpGTChAkABALBqlWrHjx40LVrVwBCoTA2NlZtszdv3ty7d29RUZGtrS2Ap0+fcuizdtGvvKN8sGPHjps3b9rZ2SUmJgoEAplMVlJSUlRURC9kMlndO3VvSqVSVWLFqVOnFhYWGjb/Sr+PHj1655137t69KxQKo6KiTExMfH19i4qKPDw8jh496qlBJcd58+YlJyefPXvW09NTLBZnZmY6Ojpy6LkWYSLUiMePH69YsQLA7t27vby8Zs2alZqaSvuiqs5nmzZt3NzcVHfq9lcrKioeP34cEBCQk5Nz6NChqVOnavsDacSGDRs2btxYXFxMJXf+/Pl58+bV1NSMGTNm//79dJFQbTw9PZOTk+ly//nz5zMyMvz9/bnyXMtoOxQ3Y5RKJd008+6779I7gwYNatCXHxgYSAiJjIwE4O7uXl1drdUPpBE5OTk0ko8ePTo3N3f69OkABAJBcHCwQqHQ3H5oaCiAhQsXbtmyBcDHH3+suc0mAouE6vP999+fPn3axsZm69at9E5UVJREIikqKqrbEZXJZK/rndKsbe+9996GDRsyMzMPHjxIf7vNkWfPnikUCqFQeOzYsT179uzbt08oFO7fvz8wMJAT+6oSBnTrvOaltZoQ2n4KNFeeP39O920fPnxYbSOq0BcVFQXA1dW1+QbD6urqFi1aGBgYlJeXK5XKxYsX37t3j0P79+7dA+Ds7Pzw4UMAjo6OHBrXLkyEavLOO+/g9/6k5tTU1HTu3BnADz/8wIlBrUCD1e3bt/kwXlVVRUVeWlpqamoqEAh0ZlspO1mvDgcOHDh69KhIJNq9ezcnBg0NDUNCQgCsWbPmr8m/mwtc1WB9JS1atHB1dVUqlY8ePXJzcyOE3L9/n4+GGh8mwgaTn5+/aNEiANu2bWvXrh1XZidPnuzt7f3kyZN9+/ZxZbOR4aoa+d/bz8zM5FXtjQ8TYYP56KOPxGLxsGHDZsyYwaFZAwOD5cuXA1i7dm0zDYZ1a7DygUp79IK/hhoZJsKGERcXFxMTY2FhER4ezvm2qUmTJnXr1u3p06d00aLZwbc2VCLnO+Q2MkyEDaC4uDgoKAjApk2bXFxcOLcvEAjoyHDdunWVlZWc2+cbT09PU1ORQtGFp/3IqkjId8htbLQ9M9ScoP3PN954g5PV51eiVCrp6fJdu3bx1ASv2NsTgPC0r7OgoACApaVlcXGxQCAwMzPj739EY8IiYX1JTEzct2+fmZlZZGQkf4Wy6aZnAF9++WVFRQVPrfCHuzsA8BSiWrVqZWtrW1paKpPJ7O3tKyoqnj59yktLjQsTYb0oKyubNWsWIWTt2rXu9IfGG++8806fPn1evHgRERHBa0N84OEBAPwN1nRygpSJsF6MHj06Ozvb19f3k08+4bstgUBAN4WvX7++2QVDKkL+BmsvTZAyEeoLcrn83LlzALZt22ZoaHj58mW+pwTGjh3r6+ubk5MTHh7Oa0OcQ88q8SpCCwuLkpISnZqb0fagtBlQWVlJz+zu37+fbpEZN24c340eP34cgI2NjUQi4bstDnn4kACEv32dlZWVSqWSELJ27VoAbdq04aulRoSJsF7s2bMHgJeXV25urqWlpUAguH79Oh8NSaXSuXPn5ubmEkJat24N4IsvvuCjIZ6oqSGmpkQgILzu67x48WKrVq0ADB8+nMdmGgsmwnpRVVVFFwYPHjxIC9a//fbbfDQ0a9YsAGPGjHn+/LmZmRmA8PBwPhrij65diaUlSU/ny35YWBhN1+3t7Z2RkcFXM40IE2F9+eGHHwC4u7vn5OTQ1LTXrl3jtokzZ84IBAITE5O0tDSaq7PZPemfPiW//FJ7nZTEsfHq6uoFCxbQYdTs2bOrqqo4bkBLMBHWl5qaGjoZEBUVFRwcTOMVh/bLyspcXV0BbNiw4eDBgwBEItGzZ884bKIROHyY2NgQWmHJz49Ly2Kx2M/PD4CpqWlkZCSXprUNE2ED2Lt3LwA3N7fc3FwaDK9cucKVcfqM7969+4sXL2hCsYiICK6MNxqHD5PPPiPjxxPCqQhTUlI6dOgAoH379px3QLQOE2EDUAXDyMjIZcuWARg1ahQnlpOTkw0NDY2MjFJSUiZPngxg6NChdBqweXH4MAkPJ59/Tn76ifj5kZISonl5pf3799Ph8cCBA+mUlY7BRNgwVHkoJBIJTS994cIFDW3K5XKaKz4kJCQuLg6AhYVFPbPENzWoCMvKiJ8f6d+f7NlDAOLjQ7ZtI2qUrqqurqY9fx0bBL4EE2HDqJuHgp54GDlypIY2ly5dCsDT0zM3N7d9+/YAduzYwYm3jQ8VISHk55+JlRXZupVYWRGAAMTCgrz/Pqn/I0sikQwdOhSAiYlJc+yZ1x8mwgZDZ02cnJzEYjHN9XT+/Hm1raWmptLUKZcuXfrggw8A9O/fvzkeDhCLyYYN5MUL8ttvtXcuXiSEkPJyEhVF/PyIQFCrRg8P8s03BX/fsUxNTe3YsSOAdu3acTjwbpowETYYhULh7e0NYM+ePfTEg7+/v3qmqqure/XqBWDx4sU0gbeJiUk6f0tsvFFVRQYNIgBZtuy1r3n6lISGEicnAhA/vzWGhob+/v7R0dF/7WQePHiQJoN88803c3Jy+HW9CcBEqA6HDx8G0KFDB7FYTLdunD17Vg07a9asAeDs7JyXl0c3A2zcuJFzbxuBuXMJQOzt/wiDr6Omhhw7Rt5//2NVYXoHB4dly5Y9ePCAEFJTU1N3EFhZWdkY3msbJkJ1UB29/e6777744gsAQ4YMaaiRe/fu0dR9CQkJ8+bNA9CzZ8/mOPewaxcBiKkpuXq1Ae/KycnZtGkTnW0GIBAIBgwY0KNHDwDGxsbNbp+QJjARqsmRI0cAODo65ufn0xKWSQ3ZIaJQKN544w0AQUFBly9fNjAwMDIyunnzJm/+8sXFi8TYmABE7YSptD62paUljYqtW7dWr1vRfGEiVBNVMNy5c+eGDRsmT558//79+r+dFlSgHVo63bp69Wr+vOWJx4+JrS0ByGefaWqquLiYjrR1bDdMfWAiVJ+ffvoJgL29fXl5eUPfm5WV5e/vf/LkySVLltC9yM1u/FNaWjplymoTE/moUaSmRn07cXFx0dHRBQUFAwcOVHt03axhlXrVhxDi4+OTmprq4uISFBQkFAqtra1V9c/oBV3DeB2pqam+vr6EkOTk5D59+jSa55pDCJk8eXJMTMyoUdMOHtxnZaW+KR8fn5s3b964cePDDz+8fft2amoqHRnqD6wqk/oIBILAwMDU1NSsrCwa0F5J3cqELVu2tLa2phcWFhZRUVE1NTWfffZZ81IggC+//DImJqZly5abNwdrokAAxcXFAIRCoUwmoxeceNiMYJFQU/bt2xcbG9uxY0eZTFZcXFxcXFy3KBr9hb2Ojh07lpSUPHv2jO6NbC7Exsb+4x//oBdjxozR0Jqtra1EIsnNzfXy8iosLJRIJDY2Nly42WxgIuSdv8pSKpWWlJRIJJIdO3aUlZWdPXt28ODBjelSYmKiiYmJk5MTLRvcoPfeu3evf//+xcXFmzZt+pv4X39MTU0rKyvLy8tFIlF1dXVlZSU9s6s/sO4o79Di2K/8JzMzs1WrVq1YseLChQuN5k/v3r1TUlLq3qG1u1XdZpFIZGVlVbcLrbpDCJk2bVpxcfHUqVM5UWBlZWVlZWWLFi0IIdXV1aampvqmQIAletIqxcXFdMPNmTNnGqdFekpDIBA4Ojq2a9eOnopsEKampl5eXnRC+NKlSxr6IxaLAdjY2OTkFLi7e3fr1puLT9nMYJFQmwiFwkWLFq1YsSIkJOTixYt8NyeTyWgtjS1btixcuFB1n9buVnWYVdW865b4lkqlMpns2bNntDZ9ixYt5s+f/+2330ZGRmpSnaqkRNGz5zCRyFwma/XgwR2e8yo3VbT9FNB3SkpK6IabhIQEvtuaOXMmgH79+tWou66nysGxceNGWkexVatWmhy0TUkhAOnRg1y7VnvyUA9hItQ+69evB/DGG2/w2krdLFKa2FGd9rh3715gYCCASZMmqW0tKYkAZNAgkpBAANLwHbi6AMvArX3mz5/v4NDOyKhnQgJf5dDKy8tpLY3Vq1fTU/xqM3To0OnTp1dWVs6dO3fHjh0tW7aMjo4+evSoetZkMgAQif640Ee0/RRgEELIli1ygPTrx5d9mkWqR48enJzSKCgoaNu2LYDw8PDt27cDsLe3LyoqUsPUvn0EIFOnkv/8hwBk+nTNvWt+sEjYJJgzx6RtW1y5gpMnuTd+5cqVnTt3GhkZRUREqE7xaUKrVq2o9pYsWTJu3Lj+/fubm/feuFGdEt80AAqFf1zoIUyETQILC9BVt5AQcLt7orKy8sMPP1QoFMuWLaOn+Dlh0qRJ48dP6dHjxwULHCIifhKLj23caHvuXIPtsO4omAibDvPmwcEBKSk4cYJLs6tWrUpPT/f09Pz888+5tAts3/7jrVujfv7Z4O5du8WLQQhmzUJDS7mZmaFjR7RpUyvChi9b6gTa7g8z/mDrVgKQXr0IVwlH62aR4sbin/nuOwIQGxvy/Dnp2pUA5PPP1bETF0fkclJaSjIzSXY2x042fZgImxAVFaRdOwKQ2FgOrFVXV/fs2RPAp59+yoG5V6FUkmHDCEDef59cvUoMDYmREUlJabAdZ2eyZg0hhERGkv/8h2svmzy6v2NGLpcPGTLkypUrpqam1r9jZmZW98/X3bGyshIIBI3mqqkpli7FsmXIzeXA2vr161NTU52dnVevXs2BuVchEGD3bnTvjshI/POfmD8f27Zh9mxcuQKjhvyyXF1x+zYePuTJzSaPtp8CvKPK3qUGtC8XFBTUaN7K5SQ6+o/CRmqnO0pPT1dlkeLKt9cRGkoA4uRE8vKIjw8JC6tXd7q8nMTHk+BgkpJC/P3J/fskMJBFQl0kIyPjm2++EQgEERERU6ZMKfoduVxeUVFRVIdX3ikqKgKwe/fusWPHBgQENILDJib49VccPozLl9G6NX78EbNmNdiIUqmcOXOmXC7/6KOPhg0bxoObf2LxYhw+jNRUnDqF69fxN10HpRKpqUhIQEICLl6EXA4A9NSEuzt69sSxYwgM5NvfJocui1D1W5wzZ46vr29ZWZmDg4ODg0P9Lcjl8pkzZx44cGDr1q2NI0LKvHkIDsb33wPAiRP49Ve0bAmhEEJh7YW1Nb2ureP9Elu2bLl8+bK9vX1oaGgjeGtkhIgIPHkCd/daBT55Ajs7qFzLzERiIhITkZSEoqLamwYG6N0bw4YhMBDJyQCwdCm8vfVRhLrcHaUZzRwcHHJycjw8PGxtbW/fvt0gC0lJSRKJhOaJOXfuHE9+vkRICElOJrNmkQsXyJAhJCioNnv8S/+ZmBAAJiYmbdq0cXV19fHxGTJkyNtvvz1ixAg6jnVzc2vMuk7Z2cTYmNCM9bNnk2vXyP795P33iaPjn9x2dydBQeTIkT/Vh1F9tWlpbHZUh8jKyqKpLGNjY+mwsHPnzhUVFfW3QM8cqHLdDxs2jD9v60JFmJ9PRowgfn4kLo4EB5O5c8m775IxY8jgwaRnT+LiQlxcal63/YUeNQJw9OjRxvGZEJKdTSZMIP7+pLqazJ5NwsP/EF6bNmTiRBIWpo8Cqw+6KUKlUunv7w9g+vTpaq+VcZXrvqFQERJCwsPJoEH/48Xl5eW5ubkPHjy4ceNGQkIC3Zz91ltv0W1l3t7ejVZbJjubzJpFwsPJ11+T2bNJaioZM4Z8/TW5c4ezZU9dRTdFuHv3bgBt2rR58eIFXStbsmRJQ40olcpu3bqhTq77AQMG8OFtXdatI9evE7mcEEIUCvL8ecPenpiYCKB169YSicTJyQnATz/9xIeff4WKUKEgI0aQt98mDcmErO/ooAh/++03Wr7zyJEjdInM2dm5tLRUDVMxMTHQINd9Q4mNre28lZWpb4QWdl+7du2uXbsAdO3atXGCIRUhIeTmTdKiBRNhA9BBEY4dOxbAhAkT0tPTTUxMDAwM1J5TUeW637Vr17p16wC8+eab3HqrQiol7dsTgGhYIJTmjLKyssrLy3N2dgYQExPDkY9/h0z2x/zKsWNEKm2ENnUEXRNhZGQk7Y89f/6cZtSdN2+eJgZprnsHBwexWGxrawve8lB88AEBSP/+RPO4RQvcrl69OiwsDECXLl2aY9VR/UGnRJiTk0NnUKKiojZu3AjAyclJJpNpYlOpVFIx79ixgy678ZGHIjGRCATExIRwUiD00qVLAEQiUV5eXsDAgQf791ccOsSBXQY/6JQIx48fD2DUqFGZmZk0p/Uvqg1gGhAbGwvA3t5eIpHQYHjq1CnNzaooLSUuLgQgmzZxZnP48OEezs63tmwhe/YQgHTqpFHRFgaf6I4Io6OjAQiFwsePHw8aNAjAv/71L66M+/r6Ati2bdumTZsA9OM0EcW//10BkN69SXU1Zzbzrl6tMTQkQiHJza2V+IEDnFlncIqOiDA/P59mPQkLC9uxYwcNXIWFhVzZP378OAA7O7v8/Hy68e3kyZOcWD5//nzbtvZvvvnTnTuc2KtDQAAByPLl5IcfaveqcKhyBnfoiAjfe+89AH5+ftnZ2TSrNOfrY3379gWwZcsWuhvOx8dH801hcrmcxwqhN24QgYBYWpKcHOLhQQCybx/3rTA0RhdEuHbtWgDm5uYPHjwYOXIkgClTpnDeyokTJwDY2NhIJJJ27doBOH78uIY2P/30U/BaIfStt2qPu+/dSwDi5saCYRNEF0RIY9SoUaOKiooGDBhgY2MjFov5aGjAgAEANm/evG3bNgC9evXSJBhevXrV0NDQyMjo2rVrHDr5J2gwtLAgL14QT08C6ONxvSaPLoiQllkeOnQoIUShUGRmZvLU0KlTp2gwFIvF7du3BxAREaFevs3KysquXbsCCA4O5tzPPxEYWFtUfv9+ApAZM/htjtFwdKE+YUFBgYuLi0wmu3LlCo2K/OHn5+fk5LR58+bdu3evX7++qqo22aZIJKpbS8zKyorWG1PdpAXS6LWZmdm333779ddfd+rU6datW/xWCE1NhY8PzM2RlYXMTAwcyGNbDPXQ9lOAG5YvXw4gICCA74aqq6sJIUqlcsiQIfi9sp8aX7uBgYGBgcGFCxf4dpgQQkJCSHw8KS0lX35JZswgW7YQnoagDLXQhUgIQCqVOjs7S6XSCxcu0JEbr4SHh8+ZM8fGxiYtLY0u3xcVFamqiNELWl2s7k3VHYlEUlJSMmvWLLqa0kiMH485czB0KA4dwoULCAtrvKYZf4+2nwKcERISAmDEiBF8N/T8+XN6SiM6OprvtjijrOxPFY/69tWeK4yX0Z0M3IsXL7a2tj59+vT58+d5beijjz6SSqWBgYETJ07ktSEuKSuDhcUffxoaQqHQnjeMP6E7IhSJRP/+978B0AO4PLF///7Y2FiRSETPDTcb2rSBRFKbpD4/H6amMDTUtk+MWnRkTEgpLi52cXEpLCw8e/bs4MGDObefn5/v5eUlkUg0rBGtHRITsWkTPDyQmYn16+Hjo22HGL+j7f4wx/Cah4L2P4cNG9aYWcw4Rq1VTQav6FQkBFBaWuri4jGD2c4AAAIhSURBVCKRSJKSkmiiB66Ii4sbO3ashYXFr7/+Sk+sMxicoDtjQoqlpeUnn3wCYMWKFRyalUqlQUFBADZv3swUyOAWXYuEAEpLS11dXcVicUJCAldJ4GfMmLFv377BgwcnJSU1ZokYhj6ga5EQgKWl5aJFiwCsXLmSE4MJCQlRUVFmZmZ79uxhCmRwjg5GQgBlZWUuLi5isfjUqVMjRowAsHXrVnNz87qbOYVCoZWVlVAoNPrbKl4ymczb2/vp06dfffXV4sWLG+sTMPQI3RQhgM2bN3/22Wf9+vVLTk4mhBgbG9fU1Lzylebm5iplUlkKhcIpU6bQCjBBQUHfffedr6/v5cuXDdnaGoMHdFaE5eXlLi4ueXl5J0+e9Pf3X758uVQqLS4urruZk95RKpV/ffs333yzYMGCc+fODRkypEWLFikpKfTkEYPBOTorQgBfffXVkiVLTExMZs+e7eDgUPeokUgkokGvZcuWCoXiJVnKZLL+/ft36NChe/fuDx8+XLt2LbdzrQxGXXRZhIWFhY6OjuXl5X//MmNj45dkSbUaExOTn5/fvXv369evv67+EYOhObosQgC5ublLlizp1KlTWVmZ7Hdoj1QqldI/VQdz/4pAIPjvf/87bty4xvSZoW/ouAjrg1wuV8lSNWgsKiqKj48PCQmhGUcZDP5gImQwtIwOLtYzGM0LJkIGQ8swETIYWoaJkMHQMkyEDIaW+X+pgCv8cBTRLAAAAj96VFh0cmRraXRQS0wgcmRraXQgMjAyNC4wOS42AAB4nHu/b+09BiAQAGImBgiQB2JlIG5g5GDQANLMTGwQmoWNIQGkjonNAcJnh9DMMBomzuaQAeYz4mHA9TJA9aKZTYwZSAzcmmAyaCrYHSxADEZmDBdhGsLNwKjBxMjEwMQMNCGDiYU1gZUtg4mNPYGdI4OJgzOBkyuDiYs7gZFHgYeXgZePgY8/g4lfIEFAMINJUChBSDiDiUdEQUQ0g0lULEFMPINJXEJBQjKDSVIqQUo6QVoGKCCbICuXwcTNnCDMlyAnksDNliAjkeDECrSelYWZm42VjZ2Dk4ubjY1fQFBImI9NVExcVk6EVVJCRlpKvI6RgYGRARZ5Ppe/2r/wjzgA4nBbzrd/s5AJzI7UZHHYou25H8T2YU5xWNUeB2abs/Q4cAZygNW8yt7l8LnnPlg8U3yvQ8yJun0gdlLdI4ezvwzsQWwRldsOy2W4HUDss0nrHJLO64LZV353OAR5PAarUQqb4LDCcJodiF38unHfnam/wGY2T+nc/3ahL9gu0yUqB957eYDZYR/9DzyzfApWs/Tp9AOvu2+B2fw6mw58mWMLVlPXOudAxdJOMJvDMPLA94AeMNtGK2//8WI5sPqa7ff3Gr9QAruhCOhXoQt/wOwLKkIH2Pczg935sdD2AHNuJJjtLd13IO9gBpg9s3TqgY3nF4PZprahBxzLdoLZy6YIHjiaMR3MXrLR7YDCAl+wmc0p0gcuinOC7RUDACvCocM9xhYcAAAC5npUWHRNT0wgcmRraXQgMjAyNC4wOS42AAB4nH2VTW7cSAyF932KukAL/C0Wl7EdBEGQNpDxzB1mn/sjj5JdUpBCui1CUj+pPvKx6Furz4+Xb///bPMjL7dba/SXv8xs/ykR3b63OmlPn798fbTnt09PH3eeX/99vP3TlJs6nsH3d+2nt9fvH3e4vTbeUsiZ2103jRwRjTbaP+ej0p4hFNOU0e6ykTGrLoQKIX7uTmLtTlsMH7ISGoS6eZcgLuHoKT4WQm+PZiBzZ6ulWTKtL4QdQt+GeA9td97Cuo1cCANL+5aUTKOWFhsD+f8pHBDGRhGVNW09WWVVnYSub8MGuyF7Du3I/k8d076yWXpnCIM9xqo4oHlG0jIojFH4CO/mK6Hs1XGmqg5SSVVbVZEVwsrVNSyrPOnRcyktayDA2gOLoi2E0XJLqZdUNg9xkZLCHY9l7r2keJeh7L77kzRk5Q+XQXcrA6s8JaXQXOZfFt0dfRQj9s7M6qilNI+3jgRjrzMlhhWrbqeDVVM7VigpzF06JeUU6ppKqlJneCJ9VQGRQ8qUotVGXbv6qpNFD2VtHmDDq4DDtFLaYYAMtYzaeT5cl6u/W5WdKLJVciGxzL4fhTKjgZS0OActOaOayrYe1FFz35hh7rJM472iygOt7zDf+1jZhI547BnBfbQnukDZdcWp7y4xmadAMEhFVu9UPnI3bCjsQVTW1V1WBf38ePltQh4z8+n18XLOTKnjnIx1Q8/5h7nb7Jxy9fVzluGi9XNiGY4455LhGOf0MRx5DhnDwddhYhWYL1PDKvCE44OOJx4XX4VJiN3Oe5iQXJQIPDm5QBF4onKxIvCk5cJF4AnMRYwg1321ry4TWQoZQc56St0R7IHLbrAKMpmlmBFkMksxI8hklmJGkMksxYwgk1mKGUEmsxQz3qzXLqtL9NClm6wqO3F0R6ZLCbWQoTsTVTsemjS6E+clh2q9a6PV9cc/dpzffgFvA4QMuZZS5QAAAW96VFh0U01JTEVTIHJka2l0IDIwMjQuMDkuNgAAeJwtUTtu5DAMvUrKGUAW+BVJGFtNs1VygMVW7n2CHD6Pmrix/ES+n7/+vB6vi+/7kgvPzfL8bKA/Ln7uw+PA5b/77//rlifQj+8HzxJyHodOjcocJ08xLR2HTDJmHScOy0nGQTPSUwDp9CXRSK4Sx5ph35tIJkuVj9Nnii8M8QxbVo0UFXOviWXidMakCKjRXMUKynPNtGQf4Ald0ltm5QtAsMeWkqSwAd7wZQ04dwjQlqphpBVcA6JQLw/w4oCltI4qrARxePUQl4Zg2nsKl1a8TRcloh7W9qHbEIUix+GIHygLBNU99FDC/8AbzOabCC3Cf0NI9DZVSqq7ycVZbhtkKtHoCnQpgp6/RXMhYoW/nUpql0KerhuoRZSjZUJyWzBrx9o8yRtZQWv4ZC5+W1LOBgKF1ps2LAYiKm83KILMC2aSVMT3jKHv/ddcHW09v38A3oWA0fGiGagAAAAASUVORK5CYII='/></td>\n",
       "      <td>7</td>\n",
       "      <td><img align=\"left\" src=\"\"></td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 65
  },
  {
   "cell_type": "markdown",
   "id": "0d37db0d-8e48-468b-846a-3480c5f2eed4",
   "metadata": {},
   "source": [
    "### 5. Select and Export a Subset of the 75 Compounds for Docking\n",
    "As the next part of this tutorial, we'll dock a few of the 75 molecules we extracted into a protein crystal structure of p38 kinase. Since we have limited commputational resources available, we will use clustering to select a subset of the compounds.   Clustering uses chemical fingerprits to group similar chemical structures.  In this case, we will use the Butina clustering algorithm as implemented in the RDKit.  To perform the clustering, we need to generate a different chemical fingerprint format than the one we generated above when we were performing dimensionality reduction. In this case, we will use the **get_fp** method of the useful_rdkit_utils Smi2Fp class.  "
   ]
  },
  {
   "cell_type": "code",
   "id": "408075d8-ca54-4ad5-be9e-a689761f48b1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.333919Z",
     "start_time": "2025-05-06T01:16:07.323804Z"
    }
   },
   "source": [
    "smi2fp = uru.Smi2Fp()\n",
    "df['morgan_fp'] = df.SMILES.apply(smi2fp.get_fp)"
   ],
   "outputs": [],
   "execution_count": 66
  },
  {
   "cell_type": "markdown",
   "id": "e2bbf65d-17fc-48ac-97b4-8f31762761e8",
   "metadata": {},
   "source": [
    "With the fingerprint generated, we can cluster using the **taylor_butina_clustering** convenience function in useful_rdkit_utils. This adds a new field, \"cluster\" to the dataframe. "
   ]
  },
  {
   "cell_type": "code",
   "id": "212051b0-e54f-4c0e-8509-72b56c8fcb9d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.358774Z",
     "start_time": "2025-05-06T01:16:07.352998Z"
    }
   },
   "source": [
    "df['cluster'] = uru.taylor_butina_clustering(df.morgan_fp)"
   ],
   "outputs": [],
   "execution_count": 67
  },
  {
   "cell_type": "markdown",
   "id": "a8908487-25fb-4c49-a87e-0ff83008305c",
   "metadata": {},
   "source": [
    "As we did above, we can use the Pandas **value_counts** method to see how many compounds are in each cluster. The vast majority of compounds are in cluster 0. "
   ]
  },
  {
   "cell_type": "code",
   "id": "724fde60-8d4d-4acb-9dc0-aaecc6de457f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.385301Z",
     "start_time": "2025-05-06T01:16:07.382298Z"
    }
   },
   "source": [
    "df.cluster.value_counts()"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "cluster\n",
       "0    65\n",
       "1     4\n",
       "4     4\n",
       "2     1\n",
       "3     1\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 68
  },
  {
   "cell_type": "markdown",
   "id": "984419f4-b236-4185-99e8-875ad80d31e9",
   "metadata": {},
   "source": [
    "Let's select the most active compound from each cluster.  To do this we first sort the dataframe by \"IC50 (nM)\".  Once the dataframe is sorted, we can use the Pandas **drop_duplicates** methood to delete all but the first compound from each cluster. "
   ]
  },
  {
   "cell_type": "code",
   "id": "1417212e-e023-4a47-a067-9500e49755fb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.410794Z",
     "start_time": "2025-05-06T01:16:07.408239Z"
    }
   },
   "source": [
    "unique_cluster_df = df.sort_values(\"IC50 (nM)\").drop_duplicates(\"cluster\").copy()"
   ],
   "outputs": [],
   "execution_count": 69
  },
  {
   "cell_type": "markdown",
   "id": "b307d533-fcb5-40ce-87ba-aa075ca85161",
   "metadata": {},
   "source": [
    "Now we'd like to exort these 5 compounds as a csv file.  The dataframe contains a lot of columns, most of which we don't need.  Let's creat a list of the columns we'd like to export. "
   ]
  },
  {
   "cell_type": "code",
   "id": "e9f17c30-f37b-453d-8cef-6f5635934ddc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.430624Z",
     "start_time": "2025-05-06T01:16:07.429291Z"
    }
   },
   "source": [
    "columns_to_keep = [\"SMILES\",\"Name\",\"IC50 (nM)\",\"cluster\"]"
   ],
   "outputs": [],
   "execution_count": 70
  },
  {
   "cell_type": "markdown",
   "id": "2ae182c2-9a40-41d2-9ae7-86f4a09b5646",
   "metadata": {},
   "source": [
    "View these columns to ensure this is what we want. "
   ]
  },
  {
   "cell_type": "code",
   "id": "77c276c0-244e-4df1-903e-194431cc860f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.453851Z",
     "start_time": "2025-05-06T01:16:07.449768Z"
    }
   },
   "source": [
    "unique_cluster_df[columns_to_keep].sort_values(\"cluster\")"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "                                               SMILES  \\\n",
       "9   Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)...   \n",
       "0   Clc1cccc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c...   \n",
       "54  CC(C)(C)NC(=O)C(N(C(=O)Cc1cncc2ccccc12)c1ccc(c...   \n",
       "74   Fc1cncc(CN(C(=O)Cc2cncc(F)c2)c2ccc(cc2)C2CNC2)c1   \n",
       "3   Clc1cccc(CN(C(=O)Cc2cnc3ccccn23)c2ccc(cc2)-c2c...   \n",
       "\n",
       "                          Name  IC50 (nM)  cluster  \n",
       "9   US20240293380, Compound 12       15.0        0  \n",
       "0    US20240293380, Compound 1      365.0        1  \n",
       "54  US20240293380, Compound 63     1027.0        2  \n",
       "74  US20240293380, Compound 83     5225.0        3  \n",
       "3    US20240293380, Compound 4     1146.0        4  "
      ],
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SMILES</th>\n",
       "      <th>Name</th>\n",
       "      <th>IC50 (nM)</th>\n",
       "      <th>cluster</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>Fc1cc(Cl)cc(CN(C(=O)Cc2cncc3ccccc23)c2ccc(cc2)...</td>\n",
       "      <td>US20240293380, Compound 12</td>\n",
       "      <td>15.0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Clc1cccc(CN(C(=O)Cc2nnc3ccccn23)c2ccc(cc2)-c2c...</td>\n",
       "      <td>US20240293380, Compound 1</td>\n",
       "      <td>365.0</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>54</th>\n",
       "      <td>CC(C)(C)NC(=O)C(N(C(=O)Cc1cncc2ccccc12)c1ccc(c...</td>\n",
       "      <td>US20240293380, Compound 63</td>\n",
       "      <td>1027.0</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>74</th>\n",
       "      <td>Fc1cncc(CN(C(=O)Cc2cncc(F)c2)c2ccc(cc2)C2CNC2)c1</td>\n",
       "      <td>US20240293380, Compound 83</td>\n",
       "      <td>5225.0</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Clc1cccc(CN(C(=O)Cc2cnc3ccccn23)c2ccc(cc2)-c2c...</td>\n",
       "      <td>US20240293380, Compound 4</td>\n",
       "      <td>1146.0</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 71
  },
  {
   "cell_type": "markdown",
   "id": "1fc31a16-7c1b-421e-a2ae-81cbd2c1515e",
   "metadata": {},
   "source": [
    "Finally, export the five molecules as a csv file. "
   ]
  },
  {
   "cell_type": "code",
   "id": "1b42308a-4e33-44d5-9543-90973956ce52",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.478124Z",
     "start_time": "2025-05-06T01:16:07.475555Z"
    }
   },
   "source": [
    "unique_cluster_df[columns_to_keep].sort_values(\"cluster\").to_csv(\"US20240293380_examples.csv\",index=False)"
   ],
   "outputs": [],
   "execution_count": 72
  },
  {
   "cell_type": "markdown",
   "id": "7a51cd9e-d3fa-4093-9aae-5c2b2e8a549e",
   "metadata": {},
   "source": [
    "These structures can be docked into the PDB structure [7LME](https://www.rcsb.org/structure/7lme) of the SARS-CoV-2 3CLPro. For more information on compounds similar to those in US20240293380, please see [\"Structure-Based Optimization of ML300-Derived, Noncovalent Inhibitors Targeting the Severe Acute Respiratory Syndrome Coronavirus 3CL Protease (SARS-CoV-2 3CLpro)\"](https://pubs.acs.org/doi/10.1021/acs.jmedchem.1c00598)"
   ]
  },
  {
   "cell_type": "code",
   "id": "72e13ada-349e-48c1-94f5-bab3f8840722",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.498698Z",
     "start_time": "2025-05-06T01:16:07.497572Z"
    }
   },
   "source": [],
   "outputs": [],
   "execution_count": null
  },
  {
   "cell_type": "code",
   "id": "03969c6e-4ec5-4c1a-85c3-9d9d9b6fe52c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-05-06T01:16:07.525043Z",
     "start_time": "2025-05-06T01:16:07.523751Z"
    }
   },
   "source": [],
   "outputs": [],
   "execution_count": null
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
